跨域的幾種方法

什么是跨域

瀏覽器出于安全方面的考慮,只允許客戶端與本域(同協(xié)議、同域名、同端口,三者缺一不可)下的接口交互。不同源的客戶端腳本在沒有明確授權(quán)的情況下,不能讀寫對方的資源,這被稱為同源策略。

同協(xié)議:如都是http或者https
同域名:如都是http://xxx.com/ahttp://xxx.com/b
同端口:如都是8080端口

而有時候,我們不得不在一個客戶端下訪問不同域中的資源,于是需要用到一些方法來避開瀏覽器的同源策略,這些方法被稱為跨域。
實現(xiàn)跨域有如下幾種方法:

1. JSONP

JSONP(JSON with Padding)是數(shù)據(jù)格式JSON的一種使用模式,可以使網(wǎng)頁實現(xiàn)跨域請求。其原理主要利用了 HTMLscript標簽。由于script是采用開放策略,通過設置src引入不同域下的資源,所以可以通過script實現(xiàn)跨域,該方法需要后端支持。jsonp跨域的實現(xiàn)步驟如下:

  • 首先客戶端定義一個數(shù)據(jù)處理函數(shù)fun,用于處理后端服務器返回的數(shù)據(jù)。
  • 創(chuàng)建一個script標簽,并將scriptsrc設置為后端接口,并在最后加一個參數(shù)callback=fun。
  • 服務端在收到由 script標簽發(fā)出的請求后,會解析請求參數(shù),獲取callback對應的fun的字符串,然后將要返回的數(shù)據(jù)datafun拼接為一個'fun(data)'的字符串,返回客戶端。
  • 客戶端拿到響應后會放到script標簽里執(zhí)行,此時會調(diào)用fun函數(shù),參數(shù)為data。

下面來做個演示,首先為演示方便,將系統(tǒng)的hosts做如下修改:

127.0.0.1 example.a.com
127.0.0.1 example.b.com

服務器端(用server-mock啟動,保存圖片的url地址數(shù)據(jù)):

客戶端(展示隨機圖片):

請求結(jié)果:


以上例子最終實現(xiàn)了由example.a.com到example.b.com的跨域。應注意的是,因為<script>只能發(fā)送GET請求,所以jsonp只能實現(xiàn)GET請求的跨域。如果希望能實現(xiàn)其他請求的跨域,就可以用接下來介紹的一種方法——CORS。

2.CORS

CORS(全稱為:Cross-Origin Resouce Sharing)跨域資源共享,是一種通過ajax跨域請求資源的方法。瀏覽器將CORS請求分為兩大類,簡單請求(simple request)和非簡單請求(not-so-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。

簡單請求的實現(xiàn)方式即當用XMLHttpRequest發(fā)請求時,瀏覽器如果發(fā)現(xiàn)該請求不符合同源策略,會給該請求加上一個請求頭origin,origin用來說明本次請求來自哪個源(協(xié)議+域名+端口)。如果origin指定的源不在后臺允許范圍內(nèi),后臺會返回一個正常的HTTP響應,然后瀏覽器會發(fā)現(xiàn)該響應頭部信息不包含Access-Control-Allow-Origin字段,然后拋出一個錯誤,該錯誤被XMLHttpRequest的onerror函數(shù)捕獲,響應被駁回,但因為該錯誤無法通過狀態(tài)碼識別,所以HTTP回應的狀態(tài)碼還是200。如果origin在后臺允許范圍內(nèi),則服務器返回的響應,會包含Access-Control-Allow-Origin:Origin(指定的源)信息,瀏覽器此時不會拋錯,響應能正常處理。
非簡單請求是是請求方法為PUT或DELETE,又或者Content-Type為application/json的對服務器有特殊要求的請求。非簡單請求的CORS請求,會在正式通信前增加一次HTTP查詢,稱為預檢(preflight),詢問服務器當前網(wǎng)頁所在域名是否在服務器的許可名單中,如果在,則發(fā)出正式的XMLHttpRequest,之后就與簡單請求一樣,不在則報錯。
依舊用上面的例子。

服務器端(設置一個響應頭,里面包含了允許請求的域名信息)

客戶端(用ajax發(fā)請求)

最終實現(xiàn)的效果與第一個jsonp的例子一樣。

3.降域

還有一種方式,就是通過降域來實現(xiàn)跨域。即通過設置document.domain的方式,將兩個域名的domain設置為一個,如對于a.example.com和b.example.com,可以通過js設置document.domain = "example.com",實現(xiàn)跨域。
做個演示,假設在http://a.example.com:8080下有一個a.html文件,其中a.html中有一個iframe,它的srchttp://b.example.com:8080/b.html。



正常情況下,由于a.html,b.html不同源,他們之間無法正常通信,但在設置document.domain = "example.com"后,兩邊可以互相通信。
最終效果如下:

用降域方法實現(xiàn)跨域操作簡單,但是有一些缺點。比如域名只能往下設置,不能回去,比如從example.com回到a.example.com。同時如果一個子域名被攻擊,多個被降域的域名都會被連帶攻擊,有很大的安全風險。

4.postMessage

postMessage是一個web API,可以實現(xiàn)跨域通信。window.postMessage()被調(diào)用時,會在所有頁面腳本執(zhí)行完畢后,向目標窗口派發(fā)一個MessageEvent消息。語法如下:

otherWindow.postMessage(message, targetOrigin, [transfer]);

  • otherWindow表示目標窗口的一個引用,比如iframecontentWindow屬性、執(zhí)行window.open返回的窗口對象、或者是命名過或通過數(shù)值索引的window.frames
  • message表示需要發(fā)送到目標窗口的數(shù)據(jù)。
  • targetOrigin決定了哪些窗口可以接收消息,其值可以是字符串"*"(表示無限制)或者一個URI。
  • transfer是一串和message同時傳遞的Transferable 對象,這些對象的所有權(quán)將被轉(zhuǎn)移給消息的接收方,而發(fā)送一方將不再保有所有權(quán)。

MessageEvent具有如下屬性:

  • message屬性表示該message的類型。
  • data屬性為window.postMessage的第一個參數(shù);
  • origin 屬性表示調(diào)用window.postMessage()方法時調(diào)用頁面的當前狀態(tài);
  • source 屬性記錄調(diào)用window.postMessage()方法的窗口信息。

用一個與上面降域類似的例子來做演示。同樣有兩個頁面a.html和b.html,a.html中的iframesrc指向b.html。


最終實現(xiàn)a.html與b.html通信效果如下:

使用postMessage方法應注意的是,如果不希望從其他網(wǎng)站接收message,那么不要為message事件添加任何監(jiān)聽器。如果確實希望接收其他網(wǎng)站的message,那么應該始終使用origin和source屬性來驗證發(fā)件人的身份,以免被惡意的網(wǎng)站攻擊。

小結(jié)

以上就是幾種常見的跨域方法,各有優(yōu)劣,且各自都有一定的安全問題,在日常應用中,需要有針對性的使用,對可能的安全風險采取相應措施。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • CORS 實現(xiàn)CORS需要瀏覽器和服務器的共同協(xié)作。對于前端開發(fā)者來說,CORS通信與同源的AJAX在代碼方面沒有...
    饑人谷_有點熱閱讀 1,393評論 0 2
  • 什么是跨域 說到跨域必須先解釋什么是同源策略,它是由Netscape提出的一個著名的安全策略。瀏覽器出于安全方面的...
    8d2855a6c5d0閱讀 1,413評論 0 0
  • 概念:只要協(xié)議、域名、端口有任何一個不同,都被當作是不同的域。 所有具有 src 屬性的HTML標簽都可以跨域 原...
    jeffAAA閱讀 2,676評論 0 0
  • 同源策略 瀏覽器出于安全方面的考慮,為了保證用戶信息的安全,防止惡意的網(wǎng)站竊取數(shù)據(jù)。只允許與本域下的接口交互。不同...
    祝余_scrapy閱讀 496評論 0 0
  • 1. AJAX AJAX(Asynchronous JavaScript and XML),意思就是用JavaSc...
    公子七閱讀 5,267評論 0 5

友情鏈接更多精彩內(nèi)容