主要閱讀文章
CORS MDN解釋
跨來源資源共用(Cross-Origin Resource Sharing (CORS))是一種使用額外 HTTP 標頭令目前瀏覽網站的使用者代理取得存取其他來源(網域)伺服器特定資源權限的機制。當使用者代理請求一個不是目前文件來源——例如來自於不同網域(domain)、通訊協定(protocol)或通訊埠(port)的資源時,會建立一個跨來源 HTTP 請求(cross-origin HTTP request)。
CORS產生原因:
瀏覽器基於安全性考量,有同源政策(Same-origin policy)
也就是說你想要呼叫與你網站「不同源」的API時,瀏覽器一樣會幫你發request,但會把 Response 擋下來,不讓你的 JavaScript 拿到並且傳回錯誤。
何謂「不同源」?
我原本的理解是不同IP之類,但是前面的文章中有提到
Domain 不一樣就是不同源,或者是一個用http一個用https也是不同源,port不一樣也是不同源。
CORS(Cross-Origin Resource Sharing) 跨來源資源共享
呼叫API很常會遇到不同Domain的API,CORS就是為了解決這個問題。
這套規範提到如果你想開啟跨來源 HTTP 請求的話,Server 必須在 Response 的 Header 裡面加上Access-Control-Allow-Origin
。
Response可以設定Access-Control-Allow-Origin: *
,設定接受什麼域名的请求,*表示任何的origin都接受。Access-Control-Allow-Headers
,接受哪些Request HeaderAccess-Control-Allow-Methods
,限制Method
所以說,要發起跨來源 HTTP 請求並且順利收到回應的話,被Request的那一方(Server端)的Response需要在 Header 裡面加上Access-Control-Allow-Origin
,才能讓不是同源的網站去call,不然 Response 會被瀏覽器給擋下來並且顯示出錯誤訊息。
CORS 中Request 的分類
簡單請求(simple requests)
很多種情況符合簡單請求,其中一種就是不使用自定義的 Header(不帶參數),而且又是 GET 的話。
預檢請求 (Preflight request)
會先以 HTTP 的 OPTIONS 方法發request到另一個網域,確認後續真正要發的request是否可安全送出。如果Preflight request沒有通過的話,後續真正要發的request也不會被觸發。
要分辨是哪種的請求的話,可以參考這篇文章,這邊就不多做解釋
為何需要Preflight request?
使用的情境之一:由於跨站請求可能會攜帶使用者資料,所以要先進行預檢請求。
以下例子引用輕鬆理解 Ajax 與跨來源請求
如果今天沒有 Preflight Request 這個機制的話,我就可以在隨便一個 Domain 的網頁上面發送一個 DELETE 的 Request 給這個 API。剛剛我有強調說瀏覽器的 CORS 機制,還是會幫你發送 Request,但只是 Response 被瀏覽器擋住而已。
因此呢,儘管沒有 Response,但是 Server 端的確收到了這個 Request,因此就會把這筆資料給刪除。
如果有 Preflight Request 的話,在發送出去收到結果的時候,就會知道這個 API 並沒有提供 CORS,因此真的 DELETE 請求就不會送出,到這邊就結束了。
先用一個 OPTIONS 的請求去確認之後的 Request 能不能送出,這就是 Preflight Request 的目的。
Question
看到現在內心我有一些疑問,就去發問了
問題1.這兩種方式應該都會做是否同源的檢查?
Ans:
簡單請求(simple requests)有時候不會觸發同源的檢查
預檢請求 (Preflight request) 則會觸發同源的檢查
問題2.因為非簡單請求可能會帶有一些使用者資料,因此會先透過 Preflight Request 去確認後續的請求能否送出。
所以說Preflight request中會先用一個 OPTIONS 的請求去確認之後的 Request 能不能送出的這一個 OPTIONS 的請求都是先去檢查使用者是否有權限嗎?
Ans:
以氣象局 API 為例,除了須做跨域設定,也須有會員認證的授權碼才能接到資料
可參考文件第 7 頁
問題3.CORS是設定在API 的server端?
是的,所以說如果server端沒有設定CORS,就無法取得資料
其他
測試是否支援CORS的工具
使用 Google Apps Script 做中繼點跨網域遠端取得 API 資料
如果是自行練習的網頁可以參考這篇文章進行設定
JavaScript 地下城 LV 5— 全台空氣指標儀表板
未來有空再來細細研究的部分
JSONP (JSON with Padding)
也是解決跨來源請求的一種方法,但目前應該比較少人使用了。
限制:
只支援GET請求,要帶的那些參數永遠都只能用附加在網址上的方式(GET)帶過去,沒辦法用 POST。CORS支持所有類型的的HTTP请求
Fetch API
是比較新的標準,也是用來抓取後端資料用的。