跨域通信

一、跨域and同源政策

1.跨域,指的是瀏覽器不能執行其他網站的腳本。它是由瀏覽器的同源策略造成的,是瀏覽器對javascript施加的安全限制。
2.同源政策

  • 協議相同
  • 域名相同
  • 端口相同
    如:
    如,http://www.example.com/dir/page.html這個網址,協議是http://,域名是www.example.com,端口是80(默認端口可以省略)。它的同源情況如下。
    http://www.example.com/dir2/other.html:同源
    http://example.com/dir/other.html:不同源(域名不同)
    http://v2.www.example.com/dir/other.html:不同源(域名不同)
    http://www.example.com:81/dir/other.html:不同源(端口不同)
    https://www.example.com/dir/page.html:不同源(協議不同)

如果非同源,共有三種行為受到限制。
(1) Cookie、LocalStorage 和 IndexedDB 無法讀取。
(2) DOM 無法獲得。
(3) AJAX 請求無效(可以發送,但瀏覽器會拒絕接受響應)。

二、如何解決跨域問題

1.cookie

舉例來說,A網頁是http://w1.example.com/a.html,B網頁是http://w2.example.com/b.html,那么只要設置相同的document.domain,兩個網頁就可以共享Cookie。

document.domain = 'example.com';

這種方法只適用于 Cookieiframe窗口,LocalStorage 和 IndexedDB 無法通過這種方法,規避同源政策,而要使用PostMessage API。

2. frame

如果兩個窗口一級域名相同,只是二級域名不同,那么設置document.domain屬性,就可以規避同源政策,拿到DOM。

對于完全不同源的網站,目前有兩種方法,可以解決跨域窗口的通信問題。

  • 片段識別符(fragment identifier)
    URL的#號后面的部分,比如http://example.com/x.html#fragment#fragment。如果只是改變片段標識符,頁面不會重新刷新。
    父窗口可以把信息,寫入子窗口的片段標識符。
    子窗口通過監聽hashchange事件得到通知。
    子窗口也可以改變父窗口的片段標識符。
  • 跨文檔通信API(Cross-document messaging)
    window.postMessage
    父窗口aaa.com向子窗口bbb.com發消息,調用postMessage。
var popup = window.open('http://bbb.com', 'title');
popup.postMessage('Hello World!', 'http://bbb.com');

postMessage方法的第一個參數是具體的信息內容,第二個參數是接收消息的窗口的源(origin),即“協議 + 域名 + 端口”。也可以設為*,表示不限制域名,向所有窗口發送。

子窗口向父窗口發送消息的寫法類似。

window.opener.postMessage('Nice to see you', 'http://aaa.com');
  • message事件的事件對象event,提供以下三個屬性。
    event.source:發送消息的窗口
    event.origin: 消息發向的網址
    event.data: 消息內容
window.addEventListener('message', receiveMessage);
function receiveMessage(event) {
  event.source.postMessage('Nice to see you!', '*');
}

3.LocalStorage

通過window.postMessage,讀寫其他窗口的 LocalStorage 也成為了可能。

3.AJAX

同源政策規定,AJAX請求只能發給同源的網址,否則就報錯。
除了架設服務器代理(瀏覽器請求同源服務器,再由后者請求外部服務),有三種方法規避這個限制。

  • JSONP
  • WebSocket
  • CORS
    (1)JSONP是服務器與客戶端跨源通信的常用方法。最大特點就是簡單適用,老式瀏覽器全部支持,服務器改造非常小。

它的基本思想是,網頁通過添加一個<script>元素,向服務器請求JSON數據,這種做法不受同源政策限制;服務器收到請求后,將數據放在一個指定名字的回調函數里傳回來。

//網頁動態插入<script>元素,由它向跨源網址發出請求。
function addScriptTag(src) {
  var script = document.createElement('script');
  script.setAttribute("type","text/javascript");
  script.src = src;
  document.body.appendChild(script);
}
//向服務器example.com發出請求
window.onload = function () {
  addScriptTag('http://example.com/ip?callback=foo');
//該請求的查詢字符串有一個callback參數,用來指定回調函數的名字,這對于JSONP是必需的。
}

function foo(data) {
  console.log('Your public IP address is: ' + data.ip);
};
//服務器收到這個請求以后,會將數據放在回調函數的參數位置返回。
foo({
  "ip": "8.8.8.8"
});

(2)WebSocket是一種通信協議,使用ws://(非加密)和wss://(加密)作為協議前綴。該協議不實行同源政策,只要服務器支持,就可以通過它進行跨源通信。

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com

有一個字段是Origin,表示該請求的請求源(origin),即發自哪個域名。
正是因為有了Origin這個字段,所以WebSocket才沒有實行同源政策。因為服務器可以根據這個字段,判斷是否許可本次通信。
(3)CORS

  • 跨源資源分享(Cross-Origin Resource Sharing)。相比JSONP只能發GET請求,CORS允許任何類型的請求。

  • 允許瀏覽器向跨源服務器,發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制。。

  • CORS需要瀏覽器和服務器同時支持。目前,所有瀏覽器都支持該功能,IE瀏覽器不能低于IE10。

  • 整個CORS通信過程,都是瀏覽器自動完成

  • 兩種請求
    簡單請求(simple request)

請求方法
HEAD
GET
POST
//HTTP頭信息
 Accept
Accept-Language
Content-Language
 Last-Event-ID
Content-Type:只限于三個值application/x-www-form-urlencoded、
multipart/form-data、text/plain

非簡單請求(not-so-simple request)

請求方法
PUT
DELETE

或者Content-Type字段的類型是application/json

  • CORS與JSONP的使用目的相同,但是比JSONP更強大。
    JSONP只支持GET請求,CORS支持所有類型的HTTP請求。JSONP的優勢在于支持老式瀏覽器,以及可以向不支持CORS的網站請求數據。
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 什么是同源策略 瀏覽器出于安全方面的考慮,只允許與本域下的接口交互。不同源的客戶端腳本在沒有明確授權的情況下,不能...
    ezrealor閱讀 504評論 0 1
  • 歡迎關注微信公眾號:全棧工廠 本文主要參考跨域資源共享 CORS 詳解[http://www.ruanyifeng...
    liqingbiubiu閱讀 1,884評論 0 3
  • 一、瀏覽器的同源策略 1.什么是同源? 所謂“同源”指的是”三個相同“。相同的域名、端口和協議,這三個相同的話就視...
    徐國軍_plus閱讀 867評論 1 3
  • 跨域是什么 同源策略 在講解什么是跨域之前先要清楚什么是同源策略,“同源政策”(same-origin polic...
    JRG_Orange閱讀 974評論 0 52
  • 又吞下一塊高密度電餅后,薛切切舒暢地打了個嗝,渾身震動,發出蜂鳴一樣的聲音。 “呃……開啟自檢模式。”洶涌的電流在...
    黏在臉上的眼鏡閱讀 224評論 2 2