看JS高程遇到 Preflighted Reqeusts不大理解,遂百度下:
轉自:http://todoit.me/ajax-preflight/
最近在做一個 VUE 的項目的時候, 和后端的小伙伴對接口, 想方便開發, 于是要求后端的小伙伴在所有的接口都加上跨域的許可 (Access-Control-Allow-Origin)
(后來事實證明這不是一個很好的解決方案, 因為 vue-cli 提供了 proxy-table 作為 AJAX請求的代理, 只需要配置一下就好, 編譯上線也不要改動代碼)
however, 經過這次折騰, 學到了preflight request的姿勢
preflight request 預請求
當你在跨域的情況下發送一個非簡單請求時:
瀏覽器預先發送一個 OPTIONS 請求, 來查明這個跨站請求對于目的站點是不是安全可接受的 當服務端對 OPTIONS 請求返回表示支持跨域請求的 Origin, method, headers 時, 瀏覽器才會發送你所需要的真正的跨域請求
什么是簡單請求
- 只使用 GET, HEAD 或者 POST 請求方法。如果使用 POST 向服務器端傳送數據,則數據類型 (Content-Type) 只能是
application/x-www-form-urlencoded
,multipart/form-data 或 text/plain
中的一種。 - 不包含自定義請求頭
舉個栗子
1. 發送預請求
我實際向服務端提交一個跨域的POST 請求, 請求的 Content-Type 是application/json, 這是一個非簡單請求, 所以瀏覽器會發送一個 method 為 OPTIONS的預請求, 到服務端查詢是否支持該跨域請求
請求信息:
Request URL: http://stu.dev/post
Request Method:OPTIONS
Access-Control-Request-Headers:content-type
Access-Control-Request-Method:POST
Origin:http://localhost:8080
OK, 注意后面三行
Access-Control-Request-Method
: 在發出預檢請求時帶有這個頭信息, 告訴服務器在實際請求時會使用的請求方式
Access-Control-Request-Headers
: 在發出預檢請求時帶有這個頭信息, 告訴服務器在實際請求時會攜帶的自定義頭信息. 如有多個, 可以用逗號分開.
Origin
: 表明發送請求或者預請求的域
2. 服務端響應預請求
Access-Control-Allow-Headers:Content-Type
Access-Control-Allow-Origin:*
Allow:GET,HEAD,POST
服務端需要對預請求里對應的三個頭進行響應:
Access-Control-Allow-Headers:Content-Type
: 表明服務端支持該跨域請求(實際請求)的請求頭, 對應預請求里的Access-Control-Request-Headers:content-type
Access-Control-Allow-Origin:*
: 表明服務端支持跨域響應的域, 對應對應預請求里的Origin
Allow:GET,HEAD,POST
表明服務端支持該跨域請求的 Method
預請求的所有跨域頭得到允許以后(及以上三個請求頭一一對應), 瀏覽器才會發送實際請求, 所以服務端要根據預請求響應這三個請求頭
3. 發送實際請求.
4. 響應實際請求.
最后
解決辦法
如果你的跨域請求失敗, 原因是預請求得不到正確響應
檢查預請求, (那個 options 請求)的三個請求頭
Origin
,Access-Control-Allow-Headers
,Access-Control-Request-Method
服務端分別加上
Access-Control-Allow-Origin: <預請求的 Origin 內容 | * >
,Access-Control-Request-Headers:<預請求的Access-Control-Request-Headers內容>
Allow:<預請求的Access-Control-Request-Method的內容>
這幾個響應頭
over.
案例參考:
打開http://www.uscfinvestments.com/usci,查看XHR中的https://cssecure.alpsinc.com/api/v1/dailyprice/usci的請求
參考
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/AccesscontrolCORS
https://www.w3.org/TR/cors/#resource-preflight-requests
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Server-SideAccessControl#預請求