本文源自一次內部關於跨域的討論分享的總結javascript
理解跨域的重點在於:瞭解跨域產生的場景、原理html
跨域問題只在瀏覽器客戶端環境下出現,是因爲瀏覽器出於安全考慮設置的同源策略引發,因此解決跨域問題通常採用的思路有兩種:
a. 繞過瀏覽器的同源策略約束
b. 遵循新的跨域規範java
同源策略:不一樣域的客戶端在沒明確受權的狀況下,不能讀寫對方的資源
同域:協議、域名、端口號均相同
好比:ajax
http://abc.com vs https://abc.com http://ab.abc.com vs http://a.abc.com 127.0.0.1:3000 vs 127.0.0.1:4000
哪些行爲會受到瀏覽器同源策略的約束呢?json
等等canvas
哪些標籤能夠加載非同源資源?
script img link iframe
跨域方案的思路a也就是基於以上幾種標籤後端
json with padding跨域
基本原理:利用script標籤的src屬性容許加載非同源資源,加載後js解析器將執行資源代碼,目標服務器在數據外層包裹一個客戶端已經定義好的函數並返回瀏覽器
服務端接口返回一段可執行js腳本
"hello browser" => callback("hello browser")安全
優:
缺:
在淘寶(www.taobao.com)登陸後,切換到天貓(www.tmall.com),會看到頂欄已經有登陸用戶信息。打開控制檯,刷新tmall頁面,能夠看到以下jsonp請求,其中第一個即爲獲取到登陸信息的關鍵請求:
打開該請求的Response內容:
這段返回內容(本質上是js代碼)到達客戶端後,將會被解析執行
@Update :不論是post message、window.name共享、location.hash共享,這類方案的原理都是依賴消息通訊機制實現的,故更改標題
以我的常常用到的Frame代理爲例
基本原理:在目標服務器放置一個代理文件(proxy_frame.html),經過加載該代理文件和服務端進行數據交互(同域請求),返回數據經過消息通信(如post message)返回給上層應用以實現跨域數據交互
a.b.com域頁面
其實是利用窗體之間通信方式 將跨域請求轉化爲同域請求
針對高版本瀏覽器:HTML5 Web Message
針對Trident引擎低版本瀏覽器(ie6-7):window.name代理(複雜結構須要stringify,啓用隊列修改)
優:
缺:
爲了解決跨域問題出現的標準規範
經過增長一系列請求頭和響應頭,規範安全地進行跨站數據傳輸,它要求瀏覽器必須能支持CORS規範定義的請求頭和策略執行,而且服務端須要解析這些新的請求頭並按照策略返回對應的響應頭和請求的資源
分爲如下三種請求場景:
響應頭:
請求頭:
直接使用ajax(根據瀏覽器版本選擇XHR或XDR對象)或fetch便可,客戶端只需按規範設置請求頭
服務端按規範識別並返回對應響應頭,還能夠對請求域名進行過濾處理
好比使用Nginx配置:(待補充)
客戶端發起一個get請求,觀察一次成功簡單請求的請求頭與響應頭:
客戶端發起一個post請求,並設置Content-Type爲application/xml,觀察一次成功預檢+正式請求的請求頭與響應頭:
客戶端發起一個post請求,並設置設置特殊標誌位 withCredentials爲true ,觀察一次成功預檢+正式請求的請求頭與響應頭:
優:
缺:
IE6-7 徹底不支持CORS
IE8-9 僅支持不帶憑證的CORS跨域請求
創建socket長鏈接,須要驗證,本質上能夠視爲安全,不存在跨域限制
因爲資源消耗較大,除了一些特殊場景,通常不使用
將本域服務端配置成 須要跨域獲取的資源的 反向代理服務器
好比:使用Nginx配置請求轉發:proxy_pass
與frame代理模式相似,請求經過Flash來發送(proxy_flash.swf放置在同源站),利用Flash的策略文件crossdomain.xml來控制資源的共享權限,獲取目標服務器請求返回數據
---至關於把iframe改爲flash
還有例如 img ping 等等等等
跨域永遠是無奈之舉,常規狀況下不該該出現
針對少許須要跨域Get請求的場景 : JSONP還是不錯的選擇
針對整站大量跨域請求 :
—— 兼容性要求高: iFrame代理跨域/服務端反向代理
—— IE10以上兼容支持: CORS規範
檢測瀏覽器支持: 高版本使用CORS規範,低版本自動降級使用iFrame代理