喔不!是CORS

2019-03-02
2 minutes read
Featured Image

喔不!是CORS

前言

看到JS地下城5F題目的時候,心裡想「噢,這不就AJAX嗎 簡單!」
,到了實際上要抓資料的時候,發現並沒有那麼容易,一開始是透過ES6內建的fetch()來抓資料,但跳出了這個訊息

問題所在

這個訊息說明了行政院環保署的Server端不提供CORS(Cross-Origin Resource Sharing)存取。

這時內心又會有另一個問題,CORS是甚麼? 這裡引用一段MDN上的說明

Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional HTTP headers to tell a browser to let a web application running at one origin (domain) have permission to access selected resources from a server at a different origin. A web application executes a cross-origin HTTP request when it requests a resource that has a different origin (domain, protocol, and port) than its own origin.

簡單來說,XMLHttpRequestFetch API兩種AJAX的存取方式都需要遵守same-origin policy,也就是在前端呼叫另一個網域的資源需要在同一個域名下才行,例如fetch()不能在 http://127.0.0.1/ 底下呼叫 https://www.google.com/ 的資源。
雖然這兩個AJAX的呼叫方法都要遵守same-origin policy,但可以透過在伺服器上設定加入回應Access-Control-Allow-Origin的header,讓其他網域能夠存取你伺服器上的資源。(氣象局API不能直接存取的原因就是少了這個header)

解決方法

上面有提到前端的AJAX不能直接使用GET存與資料,但後端可以,所以我們的解決方法是透過自己寫的代理server來取得氣象局的AQI資料後,再自己透過HTTP將取得的資料回傳回來。

這裡使用了request來GET網頁上的資料,並使用express透過HTTP回傳回來

const request = require('request');
var express = require('express');
var app = express();

app.get(/^\/corskiller\/.*/, async function (req, res) {
    const targetURL = req.originalUrl.slice(12);
    await request(targetURL, async function (error, response, body) {
        await res.setHeader('Access-Control-Allow-Origin', '*')
        await res.setHeader('Content-Type', 'application/json');
        await res.send(body);
    });
});
app.listen(3000, function () {
  console.log('Waiting for GET');
});

架好之後只要透過正常的AJAX抓取https://localhost:3000/corskiller/<API URL>,就能獲得該API上的資料囉~

最重要的Access-Control-Allow-Origin

設定伺服器的可以允許哪些網域來存取,在這裡設為無限制

await res.setHeader('Access-Control-Allow-Origin', '*')

其他設定參數如下

  • 不限制 Access-Control-Allow-Origin : *
  • 特定域名才能存取 Access-Control-Allow-Origin : domain
  • 不啟用 Access-Control-Allow-Origin : null

之後的事情

弄了這麼一大坨之後,開開心心部屬到GCP上面,結果發現域名沒有SSL憑證,不能直接存取,覺得心好累,覺得heroku會休眠有點小討厭,所以就弄個Google Script來處理這個問題了_(:з」∠)_

參考資料

CORS - https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
Access-Control-Allow-Origin - https://developer.mozilla.org/zh-TW/docs/Web/HTTP/Server-Side_Access_Control

comments powered by Disqus