Abp vNtext中CORS OPTIONS預(yù)檢請(qǐng)求的技巧!
前后端分離模大勢(shì)所趨,跨域問題更是老生常談。
《程序員應(yīng)對(duì)瀏覽器同源策略的姿勢(shì)》一文提到三種跨域請(qǐng)求方案,重點(diǎn)講述了w3c和瀏覽器廠商推出的CORS規(guī)范。
同源策略??所謂同源是指域名、協(xié)議、端口相同。不同源的瀏覽器腳本(javascript、ActionScript、canvas)在沒有明確授權(quán)的情況下,不能讀寫對(duì)方的資源, 這是瀏覽器最基本的安全規(guī)范。
CORS是w3c和瀏覽器廠商為解決跨域資源共享問題而推出的標(biāo)準(zhǔn)方案:
瀏覽機(jī)器一旦發(fā)現(xiàn)跨域請(qǐng)求,就會(huì)自動(dòng)添加一些附加的頭信息,有時(shí)還會(huì)多出一次附加的請(qǐng)求(瀏覽器自動(dòng)完成,用戶不會(huì)察覺),服務(wù)器響應(yīng)特定標(biāo)頭Access-Control-,體現(xiàn)對(duì)跨源訪問的授權(quán)態(tài)度。
今天我主要想要聊一聊CORS中的預(yù)檢請(qǐng)求
當(dāng)前端使用腳本請(qǐng)求一個(gè)跨域資源時(shí),如果是非簡(jiǎn)單請(qǐng)求(下文會(huì)解釋),瀏覽器會(huì)自動(dòng)幫你先發(fā)出一個(gè)OPTIONS查詢請(qǐng)求,稱為預(yù)檢(cors-preflight-request),作用是詢問服務(wù)器當(dāng)前網(wǎng)頁(yè)所在的域名是否在服務(wù)器的許可名單之中,以及可以使用哪些HTTP動(dòng)詞和頭信息字段;只有得到肯定答復(fù),瀏覽器才會(huì)發(fā)出正式的跨域請(qǐng)求。

"預(yù)檢請(qǐng)求“的使用,可以避免跨域請(qǐng)求對(duì)服務(wù)器的用戶數(shù)據(jù)產(chǎn)生未預(yù)期的影響。
該請(qǐng)求header中會(huì)包含以下兩個(gè)字段:
Access-Control-Request-Method: 該字段的值對(duì)應(yīng)當(dāng)前請(qǐng)求類型,例如 GET、POST、PUT等等。瀏覽器會(huì)自動(dòng)處理。
Access-Control-Request-Headers: 該字段的值對(duì)應(yīng)當(dāng)前請(qǐng)求可能會(huì)攜帶的額外的自定義header字段名,多個(gè)字段用逗號(hào)分割。瀏覽器會(huì)自動(dòng)處理,將請(qǐng)求中非簡(jiǎn)單的header字段全部列出來,例如標(biāo)識(shí)請(qǐng)求流水的x-request-id,用于Auth鑒權(quán)的Authorization 字段。
對(duì)于OPTIONS請(qǐng)求,按照規(guī)范實(shí)現(xiàn)的服務(wù)端會(huì)響應(yīng)一組HTTP header,但不會(huì)返回任何實(shí)體內(nèi)容。如果服務(wù)端支持該跨域請(qǐng)求,建議返回204狀態(tài)碼(返回200也可以);如果不支持,建議返回403狀態(tài)碼(返回404或其他錯(cuò)誤狀態(tài)碼也可以)。
響應(yīng)的header可以包含以下字段:
Access-Control-Allow-Origin: 允許哪些域被允許跨域,例如 http://qq.com 或 https://qq.com,或者設(shè)置為* ,即允許所有域訪問
Access-Control-Allow-Credentials: 是否攜帶票據(jù)訪問(對(duì)應(yīng)fetch方法中credentials),當(dāng)該值為true時(shí),Access-Control-Allow-Origin 不允許設(shè)置為*
Access-Control-Allow-Methods: 標(biāo)識(shí)該資源支持哪些方法,例如:POST, GET, PUT, DELETE
Access-Control-Allow-Headers: 標(biāo)識(shí)允許哪些額外的自定義 header 字段和非簡(jiǎn)單值的字段
Access-Control-Max-Age: 表示可以緩存Access-Control-Allow-Methods和Access-Control-Allow-Headers提供的信息多長(zhǎng)時(shí)間,單位秒,由服務(wù)端和瀏覽器默認(rèn)值共同決定。
Access-Control-Expose-Headers: 通過該字段指出哪些額外的 header 可以被支持。
由此可見,當(dāng)觸發(fā)預(yù)檢時(shí),一次AJAX請(qǐng)求會(huì)消耗掉兩個(gè)TTL(兩次服務(wù)器交互流程),嚴(yán)重影響性能。
那么如何節(jié)省掉OPTIONS請(qǐng)求來提升性能呢?從上文可以看出,有兩個(gè)方案:
發(fā)出簡(jiǎn)單請(qǐng)求
只要同時(shí)滿足以下兩個(gè)條件,就屬于簡(jiǎn)單請(qǐng)求
(1)使用下列方法之一:
head get post
(2)請(qǐng)求的Heder是
Accept Accept-Language Content-Language Content-Type: 只限于三個(gè)值:application/x-www-form-urlencoded、multipart/form-data、text/plain
不同時(shí)滿足上面的兩個(gè)條件,就屬于非簡(jiǎn)單請(qǐng)求。很明顯,我們常見的Post請(qǐng)求且Content-Type=application/json也屬于非簡(jiǎn)單請(qǐng)求,也會(huì)觸發(fā)預(yù)檢請(qǐng)求。
>? ?如果不方便改造為簡(jiǎn)單請(qǐng)求,只有使用方案2了。
服務(wù)器端設(shè)置 Access-Control-Max-Age字段
當(dāng)?shù)谝淮握?qǐng)求該URL時(shí)會(huì)發(fā)出OPTIONS請(qǐng)求,瀏覽器會(huì)根據(jù)返回的Access-Control-Max-Age字段緩存該OPTIONS預(yù)檢請(qǐng)求的響應(yīng)結(jié)果。在緩存有效期內(nèi),該資源的請(qǐng)求(URL和header字段都相同的情況下)不會(huì)再觸發(fā)預(yù)檢。(chrome 打開控制臺(tái)可以看到,當(dāng)服務(wù)器響應(yīng)Access-Control-Max-Age時(shí)只有第一次請(qǐng)求會(huì)有預(yù)檢,后面不會(huì)了。注意要開啟緩存,去掉disable cache勾選)
但是要注意的是,該緩存只針對(duì)這一個(gè)請(qǐng)求 URL 和相同的 header,無(wú)法針對(duì)整個(gè)域或者模糊匹配 URL 做緩存(當(dāng)然也可以考慮封裝一下,固定一個(gè)接口地址,傳不同的body內(nèi)容)。
以上便是對(duì)CORS OPTIONS預(yù)檢請(qǐng)求的一些思考,希望對(duì)同學(xué)們有所幫助!
最后是Abp vNtext配置CORS的示例:
private?void?ConfigureCors(ServiceConfigurationContext?context,?IConfiguration?configuration)
{
?????context.Services.AddCors(options?=>
?????{
???????//?無(wú)阻塞跨域
????????options.AddPolicy(DefaultCorsPolicyName,?builder?=>
???????{
????????builder.SetIsOriginAllowed(_?=>?true)
?????????????.AllowCredentials()
?????????????.AllowAnyHeader()
?????????????.WithMethods(HttpMethods.Get,?HttpMethods.Post,?HttpMethods.Put,?HttpMethods.Delete)
????????????????????.SetPreflightMaxAge(TimeSpan.FromHours(24));
????????});
?????});
}

C#動(dòng)態(tài)獲取對(duì)象屬性值,這才是高效正確的姿勢(shì)!

突發(fā)!拼多多又一員工在家中跳樓自殺!
