先後端分離模大勢所趨,跨域問題更是老生常談。javascript
問題背景:前端
瀏覽器最基本的安全規範-同源策略。所謂同源是指域名、協議、端口相同。不一樣源的瀏覽器腳本(javascript、ActionScript、canvas)在沒有明確受權的狀況下,不能讀寫對方的資源。java
CORS就是w3c和瀏覽器廠商爲解決跨域資源共享問題而推出的標準方案:它容許瀏覽器向跨源服務器發出腳本請求,CORS須要瀏覽器和服務器同時支持,它的通訊過程都是瀏覽器自動完成的,不須要用戶參與。chrome
瀏覽機器一旦發現跨域,就會自動添加一些附加的頭信息,有時還會多出一次附加的請求,但用戶不會察覺,服務器響應特定標頭Access-Control-,體現跨源訪問的受權。json
今天我主要想要聊一聊CORS中的預檢請求canvas
當前端使用腳本請求一個跨域資源時,若是是非簡單請求(下文會解釋),瀏覽器會自動幫你先發出一個OPTIONS
查詢請求,稱爲預檢(cors-preflight-request
),做用是詢問服務器,當前網頁所在的域名是否在服務器的許可名單之中,以及可使用那些HTTP動詞和頭信息字段。 只有獲得確定答覆,瀏覽器纔會發生正式的XHR請求。後端
該請求header中會包含如下兩個字段:跨域
對於 OPTIONS 請求,按照規範實現的服務端會響應一組HTTP header,但不會返回任何實體內容。若是服務端支持該跨域請求,建議返回 204狀態碼(返回200也能夠);若是不支持,建議返回403狀態碼(返回404或其餘錯誤狀態碼也能夠)。瀏覽器
響應的header能夠包含如下字段:緩存
因而可知,當觸發預檢時,一次AJAX請求會消耗掉兩個TTL,嚴重影響性能。
那麼如何節省掉 OPTIONS 請求來提高性能呢?從上文能夠看出,有兩個方案:
只要同時知足一下兩個條件,就屬於簡單請求
(1)使用下列方法之一:
(2)請求的Heder是
不一樣時知足上面的兩個條件,就屬於非簡單請求。
很明顯,咱們常見的Post請求、媒體類型Content-Type=application/json也屬於非簡單請求,也會觸發預檢請求。若是不方便改造爲簡單請求,只有使用方案2了。
Access-Control-Max-Age
字段當第一次請求該URL時會發出OPTIONS
請求,瀏覽器會根據返回的Access-Control-Max-Age
字段緩存該請求的OPTIONS預檢請求
的響應結果。在緩存有效期內,該資源的請求(URL和header字段都相同的狀況下)不會再觸發預檢。(chrome 打開控制檯能夠看到,當服務器響應Access-Control-Max-Age
時只有第一次請求會有預檢,後面不會了。注意要開啓緩存,去掉disable cache
勾選)
可是要注意的是,該緩存只針對這一個請求 URL 和相同的 header,沒法針對整個域或者模糊匹配URL作緩存。(固然也能夠考慮封裝一下,固定一個接口地址,傳不一樣的body內容)。
下面是Abp vNext配置CROS的示例:
private void ConfigureCors(ServiceConfigurationContext context, IConfiguration configuration) { context.Services.AddCors(options => { // 無阻塞跨域 options.AddPolicy(DefaultCorsPolicyName, builder => { builder.SetIsOriginAllowed(_ => true) .AllowCredentials() .AllowAnyHeader() .WithMethods(HttpMethods.Get, HttpMethods.Post, HttpMethods.Put, HttpMethods.Delete) .SetPreflightMaxAge(TimeSpan.FromHours(24)); }); }); }