1.什么是同源策略及限制
1.同源策略限制從一個源加載的文檔或腳本與來自另一個源的資源進行交互。 ( 這是一個用于隔離潛在惡意文件的關鍵的安全機制。)
2.一個源包括:協議、域名、端口
(這三個有一個不一樣就是源不一樣,就是我們所說的跨域了)
http:// 協議
www.xxx.com 域名
沒指名端口默認80
3.限制:不是一個源的文檔沒有權利去操作另一個源的文檔;
主要限制在幾個方面:
-
Cookie、LocalStorage 和 IndexDB 無法讀取
--操作不了Cookie、LocalStorage、IndexDB -
DOM無法獲得
--無法獲取和操作另一個資源的DOM -
Ajax請求不能發送(同源下的通信方式)
--Ajax只適合同源的通信(跨域就不行了)
2.前后端如何通信
1、Ajax
--同源下的通信方式
2、WebSocket
--不受同源策略的限制
3、CORS
--支持跨域通信,也支持同源通信
3.如何創建Ajax
1、XMLHttpRequest對象的工作流程
2、兼容性處理
3、事件的觸發條件
4、事件的觸發順序
function ajax(url,fnSucc,fnFaild){
//1、創建一個對象(兼容IE6寫法)
var xhr = XMLHttpRequest ? new XMLHttpRequest():
new ActiveXObject('Microsoft.XMLHTTP');
//2、連接服務器,確定對象的發送方式:xhr.open(type,url,true);
xhr.open('GET',url,true);
//3、發送請求
xhr.send();
//4、接受服務器返回(響應)
xhr.onreadyStateChange = function(){
if(xhr.readyState == 4){//完成
//如果加載媒體資源需要再加上xhr.status===206
(媒體資源特別大,不是一次性返回過來的,是資源的一部分;服務端給你下發的http狀態碼是206,
這個地方不加206,是收不到響應的)
if (xhr.status === 200 || xhr.status === 304) {
fuSucc(xhr.responseText);
}else{
if(fnFaild){
fnFaild(xhr.status);
}
}
}
};
}
4.跨域通信的幾種方式
1、JSONP
1.在什么時候用:
--在出現postMessage、CORS之前一直用JSONP做跨域通信的;
2.怎么做到的:
-- 利用script標簽的異步加載來實現的;
(一個頁面是www.immoc.com,script標簽地址的域名100%不是(js的地址和域名是不一致的),
跨源了,不影響script加載)--這就是jsonp能夠實行的一個最初的基本原理;
3.怎么實現的:
--需要給服務端傳遞一個回調的名,這個回調的名就是我用加載script標簽的方式發出一個請求去,
你給我返回一塊內容,這個內容是一個js塊也就是script的塊,這個塊中有回調名加代碼就能運行了,
--原理:(利用這個發出請求了,告訴服務端callback的名稱,將來要作為函數名來返回的,既然是函數名,
要創建一個函數,所以在調jsonp的時候 ,本地必須有一個jsonp的這么全局函數,后面才能把給的數據能
執行出來,當函數來運行。)
callback后面名字叫什么都可以;
<script src="http://www.abc.com/?data=name&callback=jsonp"></script>
-告訴它一個回調的名稱,而且要在window注冊一個全局的一個函數,然后下面的createScript就是要動
態創建一個script標簽,最后返回這個東西。最后script.onload是監聽腳本的加載事件,如果響應完了,
也會響應onload,然后判斷onload是不是成功,成功了以后看能不能拿到那個數據。最后不要忘了刪除這
個函數變量window[callbackName]=null;最后往html中增加script標簽目的就是把這個請求發送出去。
3.1.1.服務器給你下發的是一個script內容,利用回調的東西,執行了后面的代碼
<script>
jsonp({
data:{
}
});
</script>
jsonp.js:
box({name:'xxx'});
function createJs(sUrl){
var oScript = document.createElement('script');
oScript.type = "text/javascript";
oScript.src = sUrl;
document.getElementsByTagName('head')[0].appendChild(oScript);
}
createJs('jsonp.js?callback=box');
function box(json){
alert(json.name);
}
2、Hash(url地址中#后面的東西)
--Hash的變動頁面不會刷新
url中?后面的叫search:search的改變是會刷新頁面的;所以search不能做跨域通信;
// 利用hash,場景是當前頁面 A 通過iframe或frame嵌入了跨域的頁面 B,跨域給B發消息
// 在A中偽代碼如下:
var B = document.getElementsByTagName('iframe');
B.src = B.src + '#' + 'data';
// 在B中的偽代碼如下
window.onhashchange = function () {
var data = window.location.hash;
};
**跨域給B發消息:
先拿到B這個窗口的地址src,然后通過hash的方式后面發一段字符串,這個字符串可以是通過
完整的json,最后通過json.stringify()把json轉成字符串發給B,你是發出去了,B能不能接收
到,B在自己的代碼中增加一個window.onhashchange,這個事件是用來監聽你當前頁面的hash有
沒有改變。之前的頁面是src,現在的頁面加一個hash,所以對B來說,你的url的hash變化了,
就可以拿到了。拿到了以后通過window.location.hash就能拿到hash的具體內容。
window.location.hash可不是拿到一個,如果hash后面等于data除了A發送過來的東西還有別的
拼接,回來要特殊處理一下。
3、postMessage(html5新增加的處理跨域通信的)
同源策略的目標就是限制跨域通信,但是實際業務中又需要跨域通信;
html5中出現了這個標準postMessage,用這個實現跨域通信;
// 窗口A(http:A.com)向跨域的窗口B(http:B.com)發送信息
Bwindow.postMessage('data', 'http://B.com');
// 在窗口B中監聽
Awindow.addEventListener('message', function (event) {
console.log(event.origin);
console.log(event.source);
console.log(event.data);
}, false);
**怎么發送:
在A窗口,給誰發送,要選中哪個窗口,調postMessage這個API,第一個參數是發送的數據部分,
這里推薦使用字符串格式;第二個是接收方那個源,*是可以給任何窗口發送(很多窗口都能接收
到你的信息,這個是不安全的),推薦的做法是加上一個源;
**發送對方怎么接受:
B窗口要做哪些事情呢?
就是要監聽message事件,
window.addEventListener('message',響應函數,true/false指定捕獲還是冒泡);
要拿的就是下面這三個參數:
//來判斷發送者的源,在你的響應程序中,你要選擇性的接收;比如我只接收來自A.com的
信息,其他的一律不接收,那么就通過event.origin這個屬性來判斷
console.log(event.origin);
console.log(event.source);//引用A窗口的對象
console.log(event.data);//發送的消息通過event.data拿到數據
4、WebSocket(不受同源策略限制的,拿來跨域通信正合適)
【參考資料】http://www.ruanyifeng.com/blog/2017/05/websocket.html
1.聲明一個webSocket對象,這個地方有兩種,ws、wss區別一個加密一個非加密,
后面指向服務器的一個地址,這樣就建立了相當于JS一個對象來管理這個鏈接。
var ws = new WebSocket('wss://echo.websocket.org');
2.請求發送出去
ws.onopen = function (evt) {
console.log('Connection open ...');
ws.send('Hello WebSockets!');
};
3.對方給消息怎么接收,通過這個參數的data來拿到
ws.onmessage = function (evt) {
console.log('Received Message: ', evt.data);
ws.close();
};
4.最后這個鏈接不用了,中斷了,監聽onclose來確定是不是關閉了
ws.onclose = function (evt) {
console.log('Connection closed.');
};
5、CORS(Ajax一個變種,fetch實現CORS通信的--新出的通信標準,可以理解為支持跨域通信的Ajax)
【參考資料】http://www.ruanyifeng.com/blog/2016/04/cors.html
Ajax是不能發送跨域通信的,瀏覽器在識別你用Ajax發送了一個跨域請求的時候,它會在你
http頭中加一個orgin,來允許跨域通信。如果不加這個頭,就是一個普通的Ajax,遇到跨域通信,
瀏覽器就會攔截了(非法的不允許請求)。
// url(必選),options(可選),then就是回調成功,回調類似ES6的promise的寫法;
catch就是捕獲錯誤。
fetch('/some/url/', {
method: 'get',
}).then(function (response) {
}).catch(function (err) {
// 出錯了,等價于 then 的第二個參數,但這樣更好用更直觀
});
*CROS為什么就能支持跨域的這種通信?
瀏覽器會攔截ajax請求,如果它覺得這個ajax請求是跨域的,它會在http請求中,加一個origin