總結-使用CORS解決跨域問題

對前端來講跨域應該是不陌生的,解決跨域的方案有不少種。而我司前端接口調用也正是CORS的方式,因此不免在聯調階段會碰見一些CORS跨域的問題,下面經過一個簡單的demo驗證一下CORS解決跨域的過程當中,對一些不清楚的知識點作一個簡單的總結html

示例 demo 已經放在GitHub 上, 其中目錄client文件夾託管客戶端代碼、server目錄做爲處理CORS的服務端,分別把兩端的代碼跑起來,就能夠進行CORS相關配置的學習了前端

對CORS的瞭解能夠先看下一下阮老師的這兩篇文章:ios

一、瀏覽器同源政策及其規避方法
二、跨域資源共享CORS詳解git

假設你已經瞭解服務端處理CORS跨域時,會配置相關的一些響應頭,以下:github

Access-Control-Allow-Credentials: true,
Access-Control-Allow-Origin: *,
Access-Control-Allow-Headers: 'header',
Access-Control-Expose-Headers: 'serve-header',
Access-Control-Allow-Methods: 'methods',
Access-Control-Max-Age: '1800', // 30min = 1800s
複製代碼

那這些響應頭都具體是神馬做用呢? 下面會結合demo來了解各參數的配置做用,並給出結果圖。express

第一個參數:Access-Control-Allow-Origin

做用:服務端容許跨域的源,也就是瀏覽器的輸入的地址。demo中爲:http://huoyun-test.djtest.cn 包括端口號80,80端口默認省略了。axios

若是把server端的origin改成: http://huoyun-online.djtest.cn, 當發送請求的時候,瀏覽器包以下錯誤: 後端

如上圖由請求頭和響應頭以及控制檯(一、二、3)三點得出:因爲CORS策略,經過瀏覽器預檢請求options得出源Origin對應的url不在CORS跨域容許的範圍類,所以呢,服務端應該設置對應的頁面域名http://huoyun-test.djtest.cn,這樣纔不會報這樣的錯誤。api

第二個參數:Access-Control-Allow-Credentials

做用:攜帶cookie跨域

若是調用接口過程當中,須要cookie的傳遞,則須要設置這個參數爲true,而且Access-Control-Allow-Origin就不能設爲星號*,必須指定明確的、與請求網頁一致的域名。 若是前端採用axios來請求接口時,需同時設置axios.defaults.withCredentials = true;

這裏若是設置 Access-Control-Allow-Origin: * ,會報以下的錯誤:

也就是上面說的Access-Control-Allow-Origin此時不能設置爲星號*,若是不須要攜帶cookie時即不設置Access-Control-Allow-Credentials響應頭,但此時前端設置了 axios.defaults.withCredentials=true;,瀏覽器也會包相似的錯誤:

即當瀏覽器經過XMLHttpRequest對象發送請求時,設置了withCredentials屬性爲true時,對應的服務端此時須要作相應的處理。

所以當先後端在CORS跨域出現問題時,經過修改demo來驗證就能夠很好的找到答案了,而不是百度了一遍,依然是處於茫然中,不知道要讓服務端幹嗎,同時做爲前端應該怎麼作,不讓本身此時成爲前端小白,有話可說...

第三個參數:Access-Control-Allow-Headers

做用:先後端須要經過header來進行數據交互時,須要設置使用到的header字段。

如前端經過設置請求頭header中的字段axios.defaults.headers.common['client-header'] = 1;, 若是此時Access-Control-Allow-Headers字段沒有設置對應的header字段,瀏覽器會報以下錯誤:

也就是說經過前端設置的自定義header字段,須要服務端在Access-Control-Allow-Headers字段中設置對應的header

第四個參數:Access-Control-Expose-Headers

做用:容許瀏覽器端可以獲取相應的header值

若是服務端接口設置了響應頭字段res.setHeader('serve-header','from->express'); 可是CORS中對應的字段Access-Control-Expose-Headers並無處理,此時經過請求響應後的header結果以下:

能夠看到雖然響應頭裏面有serve-header字段,可是卻獲取不到, 若是設置了 Access-Control-Allow-Headers: serve-header再來看下結果

此時則能夠拿到服務端設置的響應頭裏面的serve-header字段了

第五個參數:Access-Control-Max-Age

做用:控制發送預檢請求options的頻率

一、若是設置Access-Control-Max-Age: 0, 則發送請求的時候瀏覽器始終都會先發送預檢請求options。如圖

每次點擊send cors按鈕請求接口 api/getcors 時,都會發送options預檢請求

二、若是設置Access-Control-Max-Age: 1800, //預請求緩存30分鐘=1800秒 結果以下:


對應的響應頭:

點擊send cors按鈕請求接口 api/getcors 時,只會首次發送options預檢請求,接着後面再次請求時就不會發options請求了

三、在2的基礎上,若是你的Chrome瀏覽器在debug狀態,勾選上Disable cache,也是失效的 以下:

即每次都會發送預檢請求

四、這裏強調一下Access-Control-Max-Age:1800設置緩存時間,僅僅是針對已經請求過的接口如api/getcors,當點擊按鈕send cors2 第一次請求接口api/getcors2時,一樣也會發送預檢請求options

第六個參數:Access-Control-Allow-Methods

做用:請求方法的限制

這裏最後一個參數就留給讀者你去校驗了,修改下Access-Control-Allow-Methods 參數看看瀏覽器的報錯結果,體會一下...

到這裏6個參數就總結完了,下面補充一下CORS跨域時,cookie的攜帶過程

CORS跨域中cookie的攜帶

首先Cookie操做具備不可跨域特性,如:

// client 端設置
Cookies.set('cookie-value', '1', { domain: 'huoyun-test.djtest.cn' });
Cookies.set('cookie-value', '2', { domain: 'test.djtest.cn' });
Cookies.set('cookie-value', '3', { domain: 'djtest.cn' });

// server 端設置
res.setHeader('Set-Cookie', 'cookie-value=22;domain=.test.djtest.cn;path=/');
複製代碼

打開chrom調試工具:以下

即:頁面huoyun-test.djtest.cn不能夠操做test.djtest.cn的cookie,經過document.cookie讀取的時候是能夠獲取到從一級域名djtest.cn 及如下的全部子域的cookie值,而在面板中是看不見服務端設置的cookie-value=22;domain=.test.djtest.cn;path=/的值,這裏注意下!!!

那此時再請求接口api/getcors,服務端接受到的cookie值以哪一個爲準呢 ? 以下:

即:最終解析到的cookie會以client端一級域名設置的值Cookies.set('cookie-value', '3', { domain: 'djtest.cn' }); 爲準

最後

對於express中間件cors、以及cookie-parser的解析代碼都不復雜,想了解的同窗,歡迎clone demo下來debug一下,印象會深入點

參考文獻

一、瀏覽器同源政策及其規避方法
二、跨域資源共享CORS詳解
三、如何區分不一樣用戶——Cookie/Session機制詳解
四、關於cookie的深刻了解

關注咱們

公衆號@前端論道
相關文章
相關標籤/搜索