--- tags: Javascript --- 最好理解的跨網域 === [本篇遷移至 https://www.i-dont-know.xyz/2019/05/17/%25e6%259c%2580%25e5%25a5%25bd%25e7%2590%2586%25e8%25a7%25a3%25e7%259a%2584%25e8%25b7%25a8%25e7%25b6%25b2%25e5%259f%259f/#more-25](https://www.i-dont-know.xyz/2019/05/17/%25e6%259c%2580%25e5%25a5%25bd%25e7%2590%2586%25e8%25a7%25a3%25e7%259a%2584%25e8%25b7%25a8%25e7%25b6%25b2%25e5%259f%259f/#more-25) <!-- 此篇不探討深度細節。但如果內容有錯請於[粉專](https://www.facebook.com/permalink.php?story_fbid=1093571357498812&id=1061703894018892&__xts__[0]=68.ARAQKJdlJ36NEUN8gLqf9JzUs7Lx4zhdpVL4Pv603zOR814UxAxXrSzVRVQIZM3fXQ1JNulAbgSlDcAzfAy5jI5_BT5sxLyCoS0KLjAelFSRXlD-XbCh0IMUSLjtB4YHDTid3e5WrpFYCsLxu_ya4H9qUq6hHh7dypazSPgpuAJwrDrpxE86KZiXJBsfe6Sv0Q7vGoxnGK7rbkhwtPXGsG7l2zkqXKnFd-WiqnnksgUKptC9k-vyqacxyT4bXsDSszCCtP0TZ3JD8n4RRAcPNl9Ip94E0ts_sggRJ0etYwZ-BFzuVlLNACk1jhLq0-Sj4O-RBoHQnbwsBrx4khVPPSoIH5_B&__tn__=-R)下留言。 # Front-End Request(AJAX) 一般使用 AJAX 都是在相同網域下進行調用,比如你可以馬上在此打開開發人員工具(F12) -> Console 執行 ```javascript= let xml = new XMLHttpRequest(); xml.open('GET','https://hackmd.io/') xml.onload=(e)=>{ console.log(xml.responseText) } xml.send() ``` 其中 https://hackmd.io/ 和目前網址 https://hackmd.io/s/SJOwugj24 屬於在同一個 domain `hackmd.io` 但你要調用外部資源,卻沒那麼容易。 --- 先看看你最常看到的錯誤,你可以在開發人員工具測試。 ## xml1 ```javascript= let xml1 = new XMLHttpRequest(); xml1.open('POST','https://test-cors.appspot.com') xml1.send('hello world') ``` 將會告訴你 :::danger No 'Access-Control-Allow-Origin' header is present on the requested resource. ::: ![](https://i.imgur.com/Y3xprot.png) 並且你想讀取 responseText,雖然回傳狀態200 但你什麼都得不到 ![](https://i.imgur.com/UybQHjq.png) --- 再看看你希望看到的情況,你可以在開發人員工具測試 ## xml2 ```javascript= let xml2 = new XMLHttpRequest(); xml2.open('POST','https://cors-test.appspot.com/test?3') xml2.send('hello world') ... xml.responseText ``` ![](https://i.imgur.com/4gHcMce.png) **為什麼都是外部資源,為什麼xml2就可以?** 其最主要的原因是在前端 Request 的 Header 帶有 `Origin` 的屬性, 但Response 的 Header 找不到 `Access-Control-Allow-Origin`,或是 `Access-Control-Allow-Origin` 不匹配你目前網頁所在的 domain。 主管這時候就發話了:~~那不是我的問題,我請你來,你必須要負責搞定。~~ 歐不!這是後端的問題,因瀏覽器因`安全性問題`有所限制,需要後段協助讓他Pass,不要怪前端。 --- 那遇到 `Access-Control-Allow-Origin` Error 到底怎麼辦? 實際上 `Access-Control-Allow-XXX` 都是要找後端合作幫忙處理。 期間你可能使用到 `Method: OPTION` 和相關 Header(找Allow,To Google) # Back-End Request 而 Backend 不會,因為後端 Request Header 不會帶有 Origin 的屬性。當然你要帶入Origin 也不會出錯。 ```javascript= let axios = require("axios") axios({ method: 'POST', url: 'https://test-cors.appspot.com', data: 'hello world', headers: { 'Content-Type': 'text/html' }}).then((r)=>{ console.log('status: ' + r.status) console.log('data: ' + r.data) }) ``` ## Demo(可以直接按下run) <iframe src="https://runkit.com/e?base64source=bGV0IGF4aW9zID0gcmVxdWlyZSgiYXhpb3MiKQpheGlvcyh7CiAgbWV0aG9kOiAnUE9TVCcsCiAgdXJsOiAnaHR0cHM6Ly90ZXN0LWNvcnMuYXBwc3BvdC5jb20nLAogIGRhdGE6ICdoZWxsbyB3b3JsZCcsCiAgaGVhZGVyczogewogICAgJ0NvbnRlbnQtVHlwZSc6ICd0ZXh0L2h0bWwnCiAgfX0pLnRoZW4oKHIpPT57CiAgICBjb25zb2xlLmxvZygnc3RhdHVzOiAnICsgci5zdGF0dXMpCiAgICBjb25zb2xlLmxvZygnZGF0YTogJyArIHIuZGF0YSkKfSk%3D" frameborder="0" style="width: 100%;height:450px"> </iframe> --- # 第三方Rest API 那如果是第三方的API,沒辦法請對方幫我改後端,那要怎麼辦呢? 方法一: 另外做個後端再包裝API,讓前端得以調用。這也是最常見的方式。 方法二: 本篇重點就在這。最近找到個好東西 https://cors-anywhere.herokuapp.com/ 可以透過他,代理請求,將 Header,data ... 透過此網站代理出去 ```javascript= let xml1 = new XMLHttpRequest(); xml1.open('POST','https://cors-anywhere.herokuapp.com/https://test-cors.appspot.com') xml1.send('hello world') ... xml1.responseText ``` ![](https://i.imgur.com/RLR2cIq.png) 其實這也不是什麼新東西,很早以前就有了。只是之前找到的都不太好使。 該專案也有開源 https://github.com/Rob--W/cors-anywhere/ 警告:此服務很可能竊取你的資料,如Token,難保此線上服務和原始碼相同。 且穩定性不能保證,如需要此服務最好自己部署或改使用`方法一`。 -->