技術大拿干貨分享:web前端跨域問題產生及解決辦法
施列宇 | 2016-08-17 11:35
【數(shù)據(jù)猿導讀】 熟悉web前端開發(fā)的人都知道,瀏覽器在請求不同域的資源時,會受到瀏覽器的同源策略影響,常常請求資源不成功,這也就是我們常常提到的跨域問題。這類問題常常會拖延著項目的推進,困擾著前端開發(fā)者。今天,我們就來談一談前端中可能會遇到的跨域問題

來源:數(shù)據(jù)猿 作者:施列宇
熟悉web前端開發(fā)的人都知道,瀏覽器在請求不同域的資源時,會受到瀏覽器的同源策略影響,常常請求資源不成功,這也就是我們常常提到的跨域問題。這類問題常常會拖延著項目的推進,困擾著前端開發(fā)者。今天,我們就來談一談前端中可能會遇到的跨域問題。
1.跨域問題的由來
首先我們需要了解的是,前端處于項目開發(fā)過程中最接近用戶的一個區(qū)域,代碼最容易被hack獲取解析,也最容易受到攻擊。針對這個問題,互聯(lián)網(wǎng)早期探索者Netscape提出了一個著名的安全策略——同源策略:瀏覽器限制腳本中發(fā)起的跨站請求,要求JavaScript或cookie只能訪問同源的資源。這里的同源指的是,域名,協(xié)議名,以及端口號相同。正是由于這個機制,才致使我們無法用簡單的手段來請求不同域名下的資源。
2.如何解決跨域問題
2.1跨域資源共享CORS
CORS是W3C提出的一個標準——CORS跨域資源共享(Cross-Origin Resource Sharing)。它允許瀏覽器向跨域服務器發(fā)出XMLHttpRequest請求,從而克服AJAX只能同源使用的限制。
首先CORS需要瀏覽器和服務器同時支持,現(xiàn)代瀏覽器包括IE10+都支持CORS請求。
圖1 CORS瀏覽器支持進度
使用CORS跨域的時候和普通的AJAX過程是一樣的。瀏覽器一但發(fā)現(xiàn)AJAX請求跨域資源,就會自動添加一些請求頭幫助我們處理一些事情。所以說只要服務端提供CORS支持,前端不需要做額外的事情。
CORS請求分兩種,這里簡單介紹其中一種:
i)簡單請求(simple request)
滿足以下兩大條件,就屬于簡單請求。
- 請求方式是head,get,post三者中其一
- http請求頭信息不超出以下字段:Accept、Accept-Language、Last-Event-ID、Content-Type:只限于application/x-www-form-urlencoded、multipart/form-data和text/plain
瀏覽器在進行簡單請求時,伴隨著ajax請求的產生,瀏覽器會自動添加origin字段,表明請求來源。服務器會識別出源,并且決定是否返回數(shù)據(jù)給該源。
圖2 瀏覽器自動添加origin字段
如果origin并不在服務器許可范圍內,服務器會返回一個正常的http。瀏覽器接受后發(fā)現(xiàn)這個http的頭信息中不包含Access-Control-Allow-Origin字段,就知道出錯了,隨后在瀏覽器會拋出相應的error。
圖3 origin不被服務器認可從而拋出error
這里列出幾個返回http中常見的幾個CORS請求頭:
- Access-Control-Allow-Origin:該字段為必需字段,可以是指定的源名(協(xié)議+域名+端口),也可以使用通配符*代表接受所有跨域資源請求
- Access-Control-Allow-Credentials:該字段為boolean值,表示是否允許發(fā)送cookie,默認為false,即不允許發(fā)送cookie值。
- Access-Control-Expose-Headers:該字段可選。CORS請求時,XMLHttpRequest對象的getResponseHeader()方法只能拿到6個基本字段:Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma.如果想拿到其他的字段,必須在Access-Control-Expose-Headers里面指定。
圖4 CORS請求成功后,服務其返回成功的請求頭
ii)非簡單請求
非簡單請求會對服務器有特殊的要求,在正式通信之前,會增加一次http查詢請求,會額外的占用資源,并進而影響到請求速度。達觀數(shù)據(jù)在數(shù)據(jù)處理以及返回數(shù)據(jù)的過程中對性能有著極高的要求,在實際項目中并沒有嘗試這種實現(xiàn)方式。筆者本人也并未對此做過深入學習,在此就不班門弄斧了。
2.2使用jsonp進行跨域請求
Jsonp可以說是目前跨域問題的最普遍的解決方案了。在此簡要介紹一下jsonp的概念。首先,jsonp跟json只有一字母之差,但完全是兩個概念,json是一種數(shù)據(jù)存儲的基本格式,通常見于js腳本存儲數(shù)據(jù),ajax請求數(shù)據(jù)。而jsonp是一種非正式的傳輸協(xié)議,該協(xié)議的一個要點是允許用戶傳遞一個callback參數(shù)給服務端,服務端返回數(shù)據(jù)時,會將callback參數(shù)作為函數(shù)名來包裹住JSON數(shù)據(jù),這樣客戶端就可以隨意定制自己的函數(shù)來自動處理返回數(shù)據(jù)了。
Jsonp的原理是:普通資源請求都會受到跨域影響,但含有src屬性的跨域資源在調用時并不會受到影響。Jsonp就是由于這種特性被發(fā)掘并實現(xiàn)跨域的。
在使用jsonp進行跨域請求時,首先我們需要注冊一個callback回調函數(shù),這個函數(shù)需要接受一個參數(shù)。然后我們需要動態(tài)生成一個script標簽,并在請求的src中加入我們的callback名稱。
圖5 在本地定義callback函數(shù)
例如:callback名為alertMessage,然后我們在頁面中動態(tài)添加src為www.datagrand.com? callback=alertMessage的script標簽。這樣,一條請求就向服務端發(fā)送成功了。服務端在接收并識別出callback后,將想要返回的數(shù)據(jù)動態(tài)的包裹在callback括號內。
圖6 Jsonp請求成功后返回的腳本內容
Script加載成功后,會執(zhí)行本地alertMessage方法,將最終的結果alert出來。本質上,jsonp就是將需要執(zhí)行的函數(shù)的名傳遞給服務端,并在服務端將對應的數(shù)據(jù)包裝到函數(shù)參數(shù)域內,并返回到本地進行調用的過程。
2.3小眾跨域方式
除了CORS和jsonp之外還有一些比較小眾的跨域方式,在此就將這些放在一起整理出來。
i)document.domain
首先我們需要知道的是,頁面中的iframe和其父頁面的window對象是可以互相獲取到的(盡管取到的window對象不能拿到方法和屬性)。但是我們可以通過修改document.domain這一屬性,來使獲得window對象具有方法和屬性。這里需要注意的是,iframe和其父頁面的主域名必須相同。例如,在www.datagrand.com/index.html頁面中嵌入一個src為shilieyu.datagrand.com/index.html的iframe,同時修改兩個頁面的document.domain為datagrand.com。這樣就可以在互相獲取到對方頁面的window對象中,就會存在方法和屬性了。這時,在其中一個頁面中可以使用ajax請求數(shù)據(jù),另一個頁面就可以使用window對象獲取到對應數(shù)據(jù)。
ii)window.postMessage
postMessage為html5中引進的方法,該方法可以向其他window對象發(fā)送消息,無論這個window對象是否同源。
圖7 possMessage支持進度
首先是postMessage方法的參數(shù),postMessage接受兩個參數(shù),第一個為要發(fā)送的消息,該參數(shù)只能為字符串類型,第二個參數(shù)用來限定接受消息的window對象所在域。如果不想限定,可以使用通配符*允許所有域接受該消息。需要接收消息的window對象,需要監(jiān)聽自身的message事件,來獲取傳過來的消息。事件觸發(fā)時,可以通過接受參數(shù)的data值,來獲取對應的數(shù)據(jù)。舉例,如下圖所示,在a頁面中創(chuàng)建指向b頁面的iframe并在其onload階段調用postMessage方法,隨后在iframe完成時,頁面會alert出a頁面?zhèn)鬟f過去的值。也就意味著跨域成功。
圖8 使用postMessage的a頁面
圖9 接受postMessage的b頁面(http://shilieyu.datagrand.net/index.html)
iii)window.name
Window的name屬性有個很有趣的特點,在一個窗口(window)的生存周期內,所有的頁面的都是共享一個name屬性,每個頁面對window.name都有這讀寫的權限,這也就意味著,在頁面即將發(fā)生跳轉時,我們可以將想要傳遞的數(shù)據(jù)放入window.name中,在頁面跳轉成功后,新頁面可以用通過window.name獲取前頁面?zhèn)鬟f過來的值。
利用這種特性,我們可以在a頁面通過iframe的形式,先訪問存儲數(shù)據(jù)的頁面,將請求值存入iframe的window.name中,再講src設置為與a頁面同源的頁面,否則是無法通過window獲取到iframe中的屬性的(詳見window.domain中內容)
總結
跨域作為一個前端開發(fā)中經(jīng)常會遇到的門檻常常困擾著開發(fā)者們。本文對跨域問題的產生以及如何解決跨域問題進行了總結,也是希望讀者在遇到相同的困境時,能有完整的解決問題的思路。筆者也是一個才入門不久的小工程師,在此希望能與諸位共同進步,共勉。
作者簡介:
施列宇,15年畢業(yè)于西安電子科技大學,專業(yè)軟件工程,目前就職于達而觀信息科技有限公司,任職前端開發(fā)工程師,負責大數(shù)據(jù)平臺的pc與webapp的研發(fā)工作。曾在上海葡萄城信息技術有限公司wijmo項目組負責wijmo控件前端的維護以及控件在Asp.Net平臺的衍生工作。對web兼容性,前端性能提升,SEO,響應式設計以及主流前端框架有著豐富的實戰(zhàn)經(jīng)驗。
注:本文由達觀數(shù)據(jù)授權數(shù)據(jù)猿發(fā)布。
歡迎更多大數(shù)據(jù)領域企業(yè)、愛好者投稿數(shù)據(jù)猿,來稿請直接投遞至:tougao@datayuan.cn
來源:數(shù)據(jù)猿
刷新相關文章
我要評論
活動推薦more >
- 2018 上海國際大數(shù)據(jù)產業(yè)高2018-12-03
- 2018上海國際計算機網(wǎng)絡及信2018-12-03
- 中國國際信息通信展覽會將于2018-09-26
- 第五屆FEA消費金融國際峰會62018-06-21
- 第五屆FEA消費金融國際峰會2018-06-21
- “無界區(qū)塊鏈技術峰會2018”2018-06-14
不容錯過的資訊
-
1#后疫情時代的新思考#疫情之下,關于醫(yī)
-
2數(shù)據(jù)軟件產品和服務商DataHunter完成B輪
-
3眾盟科技獲ADMIC 2020金粲獎“年度汽車
-
4數(shù)據(jù)智能 無限未來—2020世界人工智能大
-
5#2020非凡大賞:數(shù)字化風起云涌時,共尋
-
6#榜樣的力量#天璣數(shù)據(jù)大腦疫情風險感知
-
7#榜樣的力量#內蒙古自治區(qū)互聯(lián)網(wǎng)醫(yī)療服
-
8#榜樣的力量#實時新型肺炎疫情數(shù)據(jù)小程
-
9#榜樣的力量#華佗疫情防控平臺丨數(shù)據(jù)猿
-
10#后疫情時代的新思考#構建工業(yè)互聯(lián)網(wǎng)新