在說跨域以前,首先須要瞭解的一個概念就是」同源策略「
。php
源=協議+域名+端口號。html
若是兩個url
的協議、域名、端口號徹底一致,那麼這兩個url
就是同源的。前端
咱們能夠經過window.origin
或location.origin
獲得當前源。ajax
https://wang.com https://ergou.com //不一樣源,域名不一致(記住:只有徹底如出一轍纔算同源) http://wang.com/index.html http://wang.com/server.php //同源 localhost 調用 127.0.1 //不一樣源 複製代碼
同源策略即:不一樣源之間的頁面,不許互相訪問數據。json
瀏覽器規定:若是JS
運行在源A
裏,那麼就只能獲取源A
的數據,不能獲取源B
的數據,即不容許跨域。後端
假設 wang.com/index.html
引用了ergou.com/1.js
,那麼就說1.js
運行在源wang.com
裏api
注意,這和ergou.com
沒有關係,雖然1.js
是從它那裏下載的.跨域
因此1.js
就只能獲取wang.com
的數據,這就是瀏覽器的功能,瀏覽器就是故意這樣設計的。瀏覽器
之因此須要使用同源策略,就是爲了保護用戶的隱私。安全
以微信爲例,源爲 https://user.weixin.com
,假設當前用戶已經登陸,而且AJAX
請求 /friends.json
能夠獲取用戶好友列表。
這個時候黑客來了,他把 https://user-winxin.com
分享給你,實際上這是一個釣魚網站,你點開這個網頁,這個網頁也請求你的好友列表 https://user.weixin.com/friends.json。
請問,這個時候你的好友列表是否是就被黑客給偷走了?
之因此會出現這個問題,其根源就在於沒法區分發送者。
微信裏面的JS
和黑客的JS
發送到請求幾乎沒有區別(referer
區別)
可是若是後臺的開發者沒有檢查 referer
,那麼就徹底沒有區別。
因此,若是沒有同源策略,任何頁面都能偷走微信裏面的數據,甚至是支付寶裏面的餘額。
有的小夥伴可能會問,既然referer
有區別,那檢查referer
不就行了?
安全原則:安全鏈條上的強度取決於安全鏈條上最弱的一環。
同時,萬一這個網站的後端開發者是一個傻叉呢?
因此瀏覽器應該主動預防這種偷數據的行爲。
總之,爲了保護用戶的隱私,瀏覽器設置了嚴格的同源策略。
若是瀏覽器不限制跨域,必定是這個瀏覽器出現了bug
。
跨域,即瀏覽器試圖執行其餘網站的腳本。可是因爲同源策略的限制,致使咱們沒法實現跨域。
爲何a.wang.com
訪問wang.com
也算跨域?
由於歷史上,出現過不一樣的公司共用域名,a.wang.com
和wang.com
不必定是同一個網站,瀏覽器謹慎起見,認爲這是不一樣的源。
爲何不一樣端口也算跨域?
緣由同上,一個端口一個公司的狀況也不是沒有的。
記住:安全鏈條的強度取決於最弱的一環,全部和安全相關的問題都要謹慎對待。
爲何兩個網站的IP
同樣,也算跨域?
緣由同上,由於IP
也是能夠共用的。
爲何能夠跨域使用CSS
、JS
和圖片等?
同源策略限制的是數據訪問,咱們引用CSS
、JS
和圖片的時候,其實並不知道其內容,咱們只是在引用。
CORS
的全稱是"跨域資源共享"(Cross-origin resource sharing)。 它容許瀏覽器向跨源服務器,發出XMLHttpRequest
請求,從而克服了AJAX
只能同源使用的限制。
若是wang.com
和ergou.com
這兩個網站都是個人,我就是想讓wang.com
去訪問ergou.com
裏面的數據應該怎麼辦呢?
只須要wang.com
在響應頭裏寫ergou.com
能夠訪問便可。這就是CORS
。
實現CORS
通訊的關鍵是服務器。只要服務器實現了CORS
接口,就能夠跨源通訊。
CORS
跨域分爲兩種請求,一種是簡單請求,另一種就是複雜請求。
只要知足如下條件的就是簡單請求:
HEAD
、POST
或者 GET
Accept
、Accept-Language
、 Content-Language
、 Last-Event-ID
、 Content-Type
(限於三個值:application/x-www-form-urlencoded
、multipart/form-data
、text/plain
)簡單請求的實現具體來講就是在信息頭中加入一個Origin
字段:
GET /cors HTTP/1.1 Origin: http://wang.com Host: api.ergou.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0 ... 複製代碼
Origin
的做用就是用來講明本次請求來自哪一個源,服務器會根據Origin
的值來判斷是否接受本次請求。
若是Origin
所表示的源不被服務器接受,即瀏覽器發現迴應的信息頭中沒有Access-Control-Allow-Origin
字段,就會自動拋出一個錯誤。
注意:這種錯誤是沒法經過狀態碼識別的,這也是經過CORS
實現跨域請求的一個弊端。
若是Origin
所表示的源被服務器端所接受,那麼服務器就會返回以下響應:
Access-Control-Allow-Origin: http://api.ergou.com Access-Control-Allow-Credentials: true Access-Control-Expose-Headers: FooBar Content-Type: text/html; charset=utf-8 複製代碼
Access-Control-Allow-Origin
:該字段是必須的。它的值要麼是請求時Origin
字段的值,要麼是一個*
,表示接受任意域名的請求Access-Control-Allow-Credentials
: 該字段可選。它的值是一個布爾值,表示是否容許發送Cookie
。默認狀況下,Cookie
不包括在CORS
請求之中。設爲true
,即表示服務器明確許可,Cookie
能夠包含在請求中,一塊兒發給服務器。這個值也只能設爲true
,若是服務器不要瀏覽器發送Cookie
,刪除該字段便可。(注意:若是要發送cookie
,不只要進行上述的設置,還要在AJAX
請求中設置withCredentials
屬性)Access-Control-Expose-Headers
:該字段可選。CORS
請求時,XMLHttpRequest
對象的getResponseHeader()
方法只能拿到6個基本字段:Cache-Control
、Content-Language
、Content-Type
、Expires
、Last-Modified
、Pragma
。若是想拿到其餘字段,就必須在Access-Control-Expose-Headers
裏面指定。所謂複雜請求,即不知足上述條件的請求就是複雜請求。
好比請求的方法是PUT
或DELETE
,或者Content-Type
字段的類型是application/json
。
複雜請求首先會發起一個預檢請求,該請求是 option
方法的,經過該請求來知道服務端是否容許跨域請求。
var url = 'http://api.wang.com/cors'; var xhr = new XMLHttpRequest(); xhr.open('PUT', url, true); xhr.setRequestHeader('X-Custom-Header', 'value'); xhr.send(); 複製代碼
上面的請求就是一個複雜請求,當瀏覽器發現這是一個複雜請求以後,就會主動發出一個預檢請求,詢問服務器是否容許本次請求。
服務器收到預檢請求以後,檢查了Origin
、Access-Control-Request-Method
和Access-Control-Request-Headers
字段之後,確認容許跨源請求,纔會作出相應的迴應。
Access-Control-Allow-Origin: http://api.wang.com Content-Type: text/html; charset=utf-8 複製代碼
不支持IE8/9
,若是要在IE8/9
使用CORS
跨域須要使用XDomainRequest
對象來支持CORS
。
咱們在跨域的時候因爲當前的瀏覽器不支持 CORS
或者由於某些條件不支持 CORS
,咱們必須使用另一種方式來跨域,因而咱們就請求一個 JS
文件,這個 JS
文件會執行一個回調,回調裏面就有咱們須要的數據。
let script = document.createElement('script'); script.src = 'http://www.wang.cn/login?username=wang&callback=callback'; document.body.appendChild(script); function callback(res) { console.log(res); } 複製代碼
回調的名字是能夠隨機生成的的一個隨機數,咱們把這個名字當成 callback
的參數傳給後臺,後臺會把這個函數再次返回給咱們並執行
ie
script
標籤,因此讀不到 ajax
那麼精確的狀態,不知道狀態碼是什麼,也不知道響應頭是什麼,它只知道成功和失敗。post
(由於是 script
標籤,因此只支持 get
請求)告誡本身,即便再累也不要忘記學習,成功沒有捷徑可走,只有一步接着一步走下去。 共勉!
做者:前端求職中_杭州_感謝內推
連接:https://juejin.im/post/5e74e6... 來源:掘金 著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。