跨域與常用方案

本文源自一次內(nèi)部關(guān)于跨域的討論分享的總結(jié)

理解跨域的重點在于:了解跨域產(chǎn)生的場景、原理

跨域問題只在瀏覽器客戶端環(huán)境下出現(xiàn)闽晦,是由于瀏覽器出于安全考慮設(shè)置的同源策略引起,所以解決跨域問題一般采用的思路有兩種:
a. 繞過瀏覽器的同源策略約束
b. 遵循新的跨域規(guī)范

瀏覽器同源策略

同源策略:不同域的客戶端在沒明確授權(quán)的情況下,不能讀寫對方的資源
同域:協(xié)議吃既、域名拒秘、端口號均相同
比如:

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

哪些行為會受到瀏覽器同源策略的約束呢号显?

  • ajax請求 XMLHttpRequest
    注意:瀏覽器并不會限制跨域請求的發(fā)出臭猜,即服務(wù)端再未做其他限制的情況下仍可收到跨域請求,瀏覽器只是限制了ajax請求返回信息的讀取押蚤、cookie寫入等操作
    擴展:服務(wù)端如何限制僅接收指定域名請求? refer?
  • fetch
  • 非同域窗體之間(比如iframe引入的情況的父子窗體)不能直接進行數(shù)據(jù)通訊或共享
  • Web 字體 (CSS 中通過 @font-face 使用跨域字體資源)
  • WebGL 貼圖
  • 使用 drawImage 將 Images/video 畫面繪制到 canvas
    等等

哪些標簽可以加載非同源資源蔑歌?
script img link iframe
跨域方案的思路a也就是基于以上幾種標簽

JSONP -- 思路滿分

json with padding

基本原理:利用script標簽的src屬性允許加載非同源資源,加載后js解析器將執(zhí)行資源代碼揽碘,目標服務(wù)器在數(shù)據(jù)外層包裹一個客戶端已經(jīng)定義好的函數(shù)并返回

服務(wù)端接口返回一段可執(zhí)行js腳本
"hello browser" => callback("hello browser")

前后端交互流程:

jsonp前后端交互流程
  • 首先在瀏覽器端注冊一個全局函數(shù)callback次屠。
  • 瀏覽器端創(chuàng)建一個script標簽,將src指向目標服務(wù)端資源地址雳刺,并帶上callback參數(shù)帅矗,告訴服務(wù)端回調(diào)函數(shù)名稱,將此script標簽插入到Dom中煞烫。
  • 服務(wù)器生成返回json數(shù)據(jù) 浑此,獲取請求中的callback函數(shù)名參數(shù),再將json數(shù)據(jù)以參數(shù)填充的方式滞详,和函數(shù)名參數(shù)拼接:callback+’(‘+json+’)’凛俱,最后將拼接完成的數(shù)據(jù)返回。
  • 瀏覽器端料饥,解析script標簽蒲犬,并執(zhí)行返回的javascript 文檔,此時數(shù)據(jù)作為參數(shù)岸啡,傳入到了客戶端預(yù)先定義好的callback 函數(shù)里(動態(tài)執(zhí)行回調(diào)函數(shù))原叮。

優(yōu)缺點對比

優(yōu):

  • 兼容性極佳,在不支持XMLHttpRequest的瀏覽器中也可以用于模擬異步請求
    缺:
  • 只允許get請求: jsonp跨域原理是通過script標簽加載跨域資源巡蘸,不可能支持post請求
  • 存在一定安全隱患: 本質(zhì)上來說奋隶,jsonp是一種腳本注入(Script Injection)行為
  • 需要服務(wù)端配合支持:如果一個接口同時需要適配jsonp和正常請求,需要特殊處理沒有錯誤處理支持
  • 如果動態(tài)腳本插入有效悦荒,就執(zhí)行調(diào)用唯欣;如果無效,就靜默失敯嵛丁:不能從服務(wù)器捕捉到 404 錯誤境氢,也不能取消或重新開始請求。(自行設(shè)置定時器碰纬,超時后沒有進入回調(diào)即判定為請求失敗 )

栗子 ——淘寶和天貓通過jsonp跨域共享cookie

在淘寶(www.taobao.com)登錄后萍聊,切換到天貓(www.tmall.com),會看到頂欄已經(jīng)有登錄用戶信息悦析。打開控制臺寿桨,刷新tmall頁面,可以看到如下jsonp請求她按,其中第一個即為獲取到登錄信息的關(guān)鍵請求:

獲取共享登錄cookie信息的jsonp請求

打開該請求的Response內(nèi)容:


response內(nèi)容

這段返回內(nèi)容(本質(zhì)上是js代碼)到達客戶端后牛隅,將會被解析執(zhí)行

利用消息通信機制實現(xiàn)的跨域請求

@Update :不管是post message炕柔、window.name共享、location.hash共享媒佣,這類方案的原理都是依賴消息通信機制實現(xiàn)的匕累,故更改標題

以個人經(jīng)常用到的Frame代理為例

基本原理:在目標服務(wù)器放置一個代理文件(proxy_frame.html),通過加載該代理文件和服務(wù)端進行數(shù)據(jù)交互(同域請求)默伍,返回數(shù)據(jù)通過消息通訊(如post message)返回給上層應(yīng)用以實現(xiàn)跨域數(shù)據(jù)交互
a.b.com域頁面

加載跨域iframe文件

實際上是利用窗體之間通訊方式 將跨域請求轉(zhuǎn)化為同域請求

前后端交互流程:(以nej框架的實現(xiàn)為例)

iframe跨域前后端交互流程
  • 假設(shè)a.b.com的應(yīng)用需要向x.y.com的服務(wù)器取數(shù)據(jù)欢嘿,首先在x.y.com域服務(wù)器上預(yù)先放置代理文件,并以iframe載入該代理文件
  • 服務(wù)器端返回帶配置的代理文件
  • 代理文件載入完成后也糊,a.b.com域的應(yīng)用將要發(fā)送的請求指令通過消息通信方式傳遞給代理文件
  • 代理文件驗證a.b.com是否在預(yù)先配置的白名單中炼蹦,如果不在則異常返回,否則直接發(fā)送請求至x.y.com域服務(wù)器
  • 服務(wù)器返回數(shù)據(jù)至代理文件
  • 代理文件通過消息通訊機制將請求結(jié)果返回給a.b.com域的應(yīng)用

窗體間消息通信方式:

針對高版本瀏覽器:HTML5 Web Message
針對Trident引擎低版本瀏覽器(ie6-7):window.name代理(復(fù)雜結(jié)構(gòu)需要stringify狸剃,啟用隊列修改)


image.png

image.png

優(yōu)缺點對比:

優(yōu):

  • 服務(wù)端無需額外支持:僅需要放置代理用的html文件即可
  • 對請求method完整支持:get掐隐、post、put等等
  • 兼容性較好:需要一些兼容處理(主要針對消息通信方式)

缺:

  • 首次請求存在延時:由于首次發(fā)起請求時需要載入代理文件钞馁,在載入代理文件之前的所有請求都會存在一定的延時
  • 低版本瀏覽器并發(fā)請求延時較大:由于低版本瀏覽器受限于消息通訊機制虑省,對于并發(fā)量大的請求返回時可能存在較大延時

Cross-Origin Resource Sharing規(guī)范 -- 簡稱CORS

為了解決跨域問題出現(xiàn)的標準規(guī)范
通過增加一系列請求頭和響應(yīng)頭規(guī)范安全地進行跨站數(shù)據(jù)傳輸僧凰,它要求瀏覽器必須能支持CORS規(guī)范定義的請求頭和策略執(zhí)行探颈,并且服務(wù)端需要解析這些新的請求頭并按照策略返回對應(yīng)的響應(yīng)頭和請求的資源

分為以下三種請求場景:


cors規(guī)范三種請求場景

附錄:對 CORS 安全的首部字段集合

相關(guān)請求頭和響應(yīng)頭(主要)

響應(yīng)頭:


響應(yīng)頭說明

請求頭:


請求頭說明

如何使用?

直接使用ajax(根據(jù)瀏覽器版本選擇XHR或XDR對象)或fetch即可训措,客戶端只需按規(guī)范設(shè)置請求頭
服務(wù)端按規(guī)范識別并返回對應(yīng)響應(yīng)頭伪节,還可以對請求域名進行過濾處理
比如使用Nginx配置:(待補充)

還是看幾個栗子:

客戶端發(fā)起一個get請求,觀察一次成功簡單請求的請求頭與響應(yīng)頭:

image.png

客戶端發(fā)起一個post請求绩鸣,并設(shè)置Content-Type為application/xml怀大,觀察一次成功預(yù)檢+正式請求的請求頭與響應(yīng)頭:

Options預(yù)檢

Post正式

客戶端發(fā)起一個post請求,并設(shè)置設(shè)置特殊標志位 withCredentials為true 全闷,觀察一次成功預(yù)檢+正式請求的請求頭與響應(yīng)頭:

Options預(yù)檢

Post正式

優(yōu)缺點:

優(yōu):

  • 標準 規(guī)范 安全
  • 對請求method完整支持:get叉寂、post、put等等
  • 完整的錯誤處理:使用XMLHttpRequest對象或FetchAPI發(fā)送請求

缺:

  • 兼容程度較低:需要高版本瀏覽器支持总珠,Trident引擎的瀏覽器需要IE10以上才完整支持
    IE6-7 完全不支持CORS
    IE8-9 僅支持不帶憑證的CORS跨域請求

其他

WebSocket

建立socket長連接,需要驗證勘纯,本質(zhì)上可以視為安全局服,不存在跨域限制
由于資源消耗較大,除了一些特殊場景驳遵,一般不使用

服務(wù)端反向代理

將本域服務(wù)端配置成 需要跨域獲取的資源的 反向代理服務(wù)器
比如:使用Nginx配置請求轉(zhuǎn)發(fā):proxy_pass


反向代理

FLASH代理

與frame代理模式類似淫奔,請求通過Flash來發(fā)送(proxy_flash.swf放置在同源站),利用Flash的策略文件crossdomain.xml來控制資源的共享權(quán)限堤结,獲取目標服務(wù)器請求返回數(shù)據(jù)
---相當(dāng)于把iframe改成flash

還有例如 img ping 等等等等

總結(jié)

跨域永遠是無奈之舉唆迁,常規(guī)情況下不應(yīng)該出現(xiàn)

針對少量需要跨域Get請求的場景 : JSONP仍是不錯的選擇
針對整站大量跨域請求 :
—— 兼容性要求高: iFrame代理跨域/服務(wù)端反向代理

—— IE10以上兼容支持: CORS規(guī)范

檢測瀏覽器支持: 高版本使用CORS規(guī)范鸭丛,低版本自動降級使用iFrame代理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市唐责,隨后出現(xiàn)的幾起案子鳞溉,更是在濱河造成了極大的恐慌,老刑警劉巖鼠哥,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件熟菲,死亡現(xiàn)場離奇詭異,居然都是意外死亡朴恳,警方通過查閱死者的電腦和手機抄罕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來于颖,“玉大人呆贿,你說我怎么就攤上這事∩ィ” “怎么了榨崩?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長章母。 經(jīng)常有香客問我母蛛,道長,這世上最難降的妖魔是什么乳怎? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任彩郊,我火速辦了婚禮,結(jié)果婚禮上蚪缀,老公的妹妹穿的比我還像新娘秫逝。我一直安慰自己,他們只是感情好询枚,可當(dāng)我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布违帆。 她就那樣靜靜地躺著,像睡著了一般金蜀。 火紅的嫁衣襯著肌膚如雪刷后。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天渊抄,我揣著相機與錄音尝胆,去河邊找鬼。 笑死护桦,一個胖子當(dāng)著我的面吹牛含衔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼贪染,長吁一口氣:“原來是場噩夢啊……” “哼缓呛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起杭隙,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤哟绊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后寺渗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體匿情,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年信殊,在試婚紗的時候發(fā)現(xiàn)自己被綠了炬称。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡涡拘,死狀恐怖玲躯,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鳄乏,我是刑警寧澤跷车,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站橱野,受9級特大地震影響朽缴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜水援,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一密强、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蜗元,春花似錦或渤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至惯豆,卻和暖如春池磁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背循帐。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工框仔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人拄养。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親瘪匿。 傳聞我的和親對象是個殘疾皇子跛梗,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,507評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 前言:對于跨域請求,很早之前就有去了解過棋弥,但因為一直關(guān)注的都是服務(wù)器后端開發(fā)核偿,故也就僅僅停留在概念的理解上而沒有機...
    ken_ljq閱讀 89,782評論 6 128
  • 題目1.什么是同源策略? 同源策略(Same origin Policy): 瀏覽器出于安全方面的考慮,只允許與本...
    FLYSASA閱讀 1,727評論 0 6
  • 跨域問題的場景和解決方案多種多樣顽染,只要是做前端開發(fā)漾岳,總會遇到。而且面試時也是必問的問題粉寞。所以自己學(xué)習(xí)總結(jié)記錄一下尼荆。...
    花開_陳鳳娟閱讀 737評論 0 0
  • 這篇文章我們來聊聊「跨域」,這個概念在很多公司的面試中會被問到唧垦,網(wǎng)上也有數(shù)不清的關(guān)于「跨域」的文章捅儒。 那我為什么還...
    水劍承王閱讀 287評論 1 1
  • 我今天剛從外面回來,坐在沙發(fā)上打開手機振亮,看到微信群里有人找我巧还,哦,我的天吶坊秸,語文濕地把我的兩篇徐水之行推送出來了麸祷!...
    聆聽色彩閱讀 595評論 0 1