熟悉web前端開發(fā)的人都知道,瀏覽器在請求不同域的資源時,會受到瀏覽器的同源策略影響,常常請求資源不成功,這也就是我們常常提到的跨域問題。這類問題常常會拖延著項目的推進,困擾著前端開發(fā)者。今天,我們就來談一談前端中可能會遇到的跨域問題。
1.跨域問題的由來
首先我們需要了解的是,前端處于項目開發(fā)過程中最接近用戶的一個區(qū)域,代碼最容易被hack獲取解析,也最容易受到攻擊。針對這個問題,互聯(lián)網(wǎng)早期探索者Netscape提出了一個著名的安全策略——同源策略:瀏覽器限制腳本中發(fā)起的跨站請求,要求JavaScript或cookie只能訪問同源的資源。這里的同源指的是,域名,協(xié)議名,以及端口號相同。正是由于這個機制,才致使我們無法用簡單的手段來請求不同域名下的資源。
2.如何解決跨域問題
2.1跨域資源共享CORS
CORS是W3C提出的一個標(biāo)準(zhǔn)——CORS跨域資源共享(Cross-Origin Resource Sharing)。它允許瀏覽器向跨域服務(wù)器發(fā)出XMLHttpRequest請求,從而克服AJAX只能同源使用的限制。
首先CORS需要瀏覽器和服務(wù)器同時支持,現(xiàn)代瀏覽器包括IE10+都支持CORS請求。
使用CORS跨域的時候和普通的AJAX過程是一樣的。瀏覽器一但發(fā)現(xiàn)AJAX請求跨域資源,就會自動添加一些請求頭幫助我們處理一些事情。所以說只要服務(wù)端提供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請求的產(chǎn)生,瀏覽器會自動添加origin字段,表明請求來源。服務(wù)器會識別出源,并且決定是否返回數(shù)據(jù)給該源。
如果origin并不在服務(wù)器許可范圍內(nèi),服務(wù)器會返回一個正常的http。瀏覽器接受后發(fā)現(xiàn)這個http的頭信息中不包含Access-Control-Allow-Origin字段,就知道出錯了,隨后在瀏覽器會拋出相應(yīng)的error。
這里列出幾個返回http中常見的幾個CORS請求頭:
Access-Control-Allow-Origin:該字段為必需字段,可以是指定的源名(協(xié)議+域名+端口),也可以使用通配符*代表接受所有跨域資源請求
Access-Control-Allow-Credentials:該字段為boolean值,表示是否允許發(fā)送cookie,默認(rèn)為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里面指定。
ii)非簡單請求
非簡單請求會對服務(wù)器有特殊的要求,在正式通信之前,會增加一次http查詢請求,會額外的占用資源,并進而影響到請求速度。達觀數(shù)據(jù)在數(shù)據(jù)處理以及返回數(shù)據(jù)的過程中對性能有著極高的要求,在實際項目中并沒有嘗試這種實現(xiàn)方式。筆者本人也并未對此做過深入學(xué)習(xí),在此就不班門弄斧了。
2.2使用jsonp進行跨域請求
Jsonp可以說是目前跨域問題的最普遍的解決方案了。在此簡要介紹一下jsonp的概念。首先,jsonp跟json只有一字母之差,但完全是兩個概念,json是一種數(shù)據(jù)存儲的基本格式,通常見于js腳本存儲數(shù)據(jù),ajax請求數(shù)據(jù)。而jsonp是一種非正式的傳輸協(xié)議,該協(xié)議的一個要點是允許用戶傳遞一個callback參數(shù)給服務(wù)端,服務(wù)端返回數(shù)據(jù)時,會將callback參數(shù)作為函數(shù)名來包裹住JSON數(shù)據(jù),這樣客戶端就可以隨意定制自己的函數(shù)來自動處理返回數(shù)據(jù)了。
Jsonp的原理是:普通資源請求都會受到跨域影響,但含有src屬性的跨域資源在調(diào)用時并不會受到影響。Jsonp就是由于這種特性被發(fā)掘并實現(xiàn)跨域的。
在使用jsonp進行跨域請求時,首先我們需要注冊一個callback回調(diào)函數(shù),這個函數(shù)需要接受一個參數(shù)。然后我們需要動態(tài)生成一個script標(biāo)簽,并在請求的src中加入我們的callback名稱。
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對象獲取到對應(yīng)數(shù)據(jù)。
ii)window.postMessage
postMessage為html5中引進的方法,該方法可以向其他window對象發(fā)送消息,無論這個window對象是否同源。
原網(wǎng)站:https://mp.weixin.qq.com/s/OSv2HqUMchoLMhtfyar30w