[第九週]透過瀏覽器交換資料 —
同源政策、CORS、第三種方式 JSONP

MiaHsu
7 min readMay 1, 2020

--

學習目標:了解什麼是同源政策、CORS 以及第三種交換資料的方式 JSONP

以下內容大部分取自文章: Huli 輕鬆理解 Ajax 與跨來源請求

在上集[第九週]透過瀏覽器交換資料 — 表單、AJAX、XMLHttpRequest

我們學到兩種方式:表單及 AJAX,而在 AJAX 發送 request 到 https://google.com 跳出錯誤訊息

ajax.html:1 Access to XMLHttpRequest at 'https://google.com/' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

意思指由於瀏覽器基於安全性考量,程式碼所發出的跨來源 HTTP 請求會受到限制,有一個東西叫同源政策(Same-origin policy),他不准我們發 request 到 https://google.com/

Same-origin policy 同源政策

簡單來說,相同 Domain 就是同源,不同 Domain 就是不同源。

MDN 同源定義

這邊要注意 https 跟 http 是不同源(因為協定不一樣),如果是接別人的 API 大多數情形都是不同源的,因此在同源政策的規定下,如果是不同源的話,預設情況就會把回傳的 response 擋掉

特別強調!!

你的 Request 還是有發出去的

而瀏覽器「確實也有收到並回傳 Response 」,重點是「瀏覽器的同源政策,不把結果傳回到 JavaScript 」。所以!如果不透過瀏覽器的話就沒有這些問題,request 愛怎麼發就怎麼發,不管怎樣都拿得到 response。

[第六週] 網路基礎 — HTTP、Request、Response 就有用 node.js request 套件成功到 https://google.com/ 的 response ,這就是差異性。

CORS

因此為了要解決不同源拿資料的問題,就有了另一個規範,「如果你想在不同的源之間傳輸資料的話,你應該怎麼做」,這個規範就叫做 CORS

如果「Server 端」想開啟跨來源 HTTP 請求的話,必須在 Response 的 Header 加上 Access-Control-Allow-Origin

這樣 Client 端透過瀏覽器發出的 request 就不會被擋住瀏覽器,正確收到 Response 了!

Access-Control-Allow-Origin

剛剛 google 的錯誤訊息,就有講到這個 Header

而打開 devTool 在 https://google.com/ 的 response header 沒有看到這個 Header。( https://google.com/ 沒有開啟所以被瀏覽器擋住了)

回過頭看看 https://reqres.in/api/users 的 response header 確實有這一行

星號就代表萬用字元,意思是任何一個 Origin 都接受
[補充說明]除了這個 header 外還有其他的可以用Access-Control-Allow-Headers 定義接受哪些 Request HeaderAccess-Control-Allow-Methods,接受哪些 Method。

簡單請求(simple requests)與預檢請求(Preflight Request)

前面有提到,儘管沒有正確收到 response 「你的 Request 還是有發出去」,Server 端也的確收到,因此假設是送出 DELETE 的 request 就還是會把資料刪除。

總不能讓人亂動 server 端的資料吧,為了避免這個問題,CORS 把 Request 分成「簡單請求」與「預檢請求」兩種

  • 簡單請求(simple requests)沒有加任何自定義的 Header,詳細定義可參考:MDN: 簡單請求
  • 預檢請求(Preflight Request)請求會先以 HTTP 的 OPTIONS 方法送出請求到另一個網域,確認後續實際(actual)請求是否可安全送出。
會先以 OPTIONS 送到另一個網域

如果這個 Preflight Request 沒有過的話,真的 Request 也就不會發送了,這就是預檢請求的目的。

時光機:[第六週] API 基礎-實際串接 Twitch API當時在串 Twitch API 的時候很痛苦,說要加上 client-id 可是加在哪?說要加參數但加在哪?加上去也不知道為什麼,現在終於有種「喔~原來是這樣的感覺」抓取 Twitch API 必須要使用預檢請求,確認 request header 包含 client-id 才能成功拿到資料

網頁前端傳資料到後端的方式

第三種 JSONP

  • 全名 JSON with Padding
  • 特性:透過 html 某些標籤的特性去繞過 同源政策 達成存取跨來源的資料。
  • 缺點:要帶的那些參數永遠都只能用附加在網址上的方式(GET)帶過去,沒辦法用 POST。
  • 現在很少人使用。

我們會發現在 html 中有些標籤像是 <img><script>,在 src 的部分可以從 https:// …. 載入圖片或是 js 檔案,這不就是跨來源的資料取得資料嗎!

所以就有人利用 src 標籤來傳遞資料,假設載入的 js 內是資料(JSON)我們就可以從預先建立好 function 取得資料。

補充:單向傳送資料的延伸應用(開信率)

我們常聽的的開信率就是運用傳送資料的原理,來知道發出去的信是否有被開啟。

做法是在信件中塞入一個 1x1 的圖片,

他的 src 就是一個網址加上相關參數

只要 loding 這張圖,就代表發一個 request 到那個網址,就知道知道有人開啟這個信件

重點整理

  • 透過「瀏覽器」交換資料會受「同源政策」的影響,不允許不同源交換資料,但在多數情況下都是不同源,因此為了解決這個問題就有了另一個規範「CORS」,如果 server 端想要開啟跨來源的請求,可以在 response 的 header 添加 Access-Control-Allow-Origin,這樣當 clinet 端透過瀏覽器正確拿到 response。
  • 「CORS」將 request 分成兩種:
  1. 簡單請求:沒有 自定義 header
  2. 預檢請求:帶有 自定義 header ,會先將 request 用 options 的方法傳到另一個網域,確認後續實際請求是否可以安全送出(例如:Twitch api 必須在 request header 帶有 client-id 跟 Authorization)

參考資料

以上有錯誤的地方歡迎指正,感謝。

--

--

MiaHsu
MiaHsu

Written by MiaHsu

每件事都是最好的安排,成為更好的自己

No responses yet