iT邦幫忙

第 12 屆 iThome 鐵人賽

1
Modern Web

強型闖入DenoLand系列 第 35

強型闖入DenoLand[34] - 淺談跨來源資源共用(CORS)與解決辦法

Node.js之父新專案Deno 1.0正式亮相| iThome

強型闖入DenoLand[34] - 淺談跨來源資源共用(CORS)與解決辦法

在談完 Web API 的實作後,今天筆者想跟大家分享後端與前端常常碰到的頭痛問題: CORS

進入正題

關於 CORS ,在 MDN web docs 上有詳細的解說,筆者把上面的內容引用過來逐一講解:

跨來源資源共用(Cross-Origin Resource Sharing (CORS))是一種使用額外 HTTP 標頭令目前瀏覽網站的使用者代理取得存取其他來源(網域)伺服器特定資源權限的機制。當使用者代理請求一個不是目前文件來源——例如來自於不同網域(domain)、通訊協定(protocol)或通訊埠(port)的資源時,會建立一個跨來源 HTTP 請求(cross-origin HTTP request)

白話文來解釋的話:就是使用者訪問了一個網站,但是該網站中有部分圖片或是其他資源並不存在於同一台伺服器上。這時候,瀏覽器就會為我們做跨來源的 HTTP 請求。

舉例:

  • CDN

    網站 A 透過 CDN 引用了相關框架做開發,這時我們可以在網頁原始碼中發現:

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  • 圖片資源

    網站 A 內嵌入了一些圖片,這些圖片來自於其他伺服器上:

    <img src="https://s4.itho.me/sites/default/files/styles/picture_size_large/public/field/image/v1_wide.jpg?itok=aqrO_0jM"/>
    

img

上圖同樣取自 MDN Web Docs 。

基於安全性考量,程式碼所發出的跨來源 HTTP 請求會受到瀏覽器限制。像是 XMLHttpRequestFetch 都遵守必須同源政策(same-origin policy)。這代表網路應用程式所使用的 API 除非使用 CORS 標頭,否則只能請求與應用程式相同網域的 HTTP 資源。

常見解法

筆者第一次處理 CORS 是因為參加了 KKBOX 線上黑客松,這個比賽需要用 KKBOX OPEN API 去開發應用,那時主辦方就有特別提到 CORS 的問題。後來在製作畢業專題時,因為有一部分使用 Vue.js 開發的應用是利用 Github-page 讓使用者做存取,導致後端程式與前端程式不同源,產生了 CORS 問題。

就筆者的粗淺觀念,處理 CORS 前必須先確定開發者的身份:

  1. 我是前端開發者
  2. 我是後端、全端開發者

確定身份後,再針對身份客製出不同的解決辦法:

我是前端開發者

如果你是前端開發者,有兩種作法:

  • 請後端工程師在 API 加入 CORS 標頭

  • 使用 CORS Anywhere

    如果今天串接的 API 是 OPEN API 或是使用者無法聯絡到 API 的開發者,那可以使用 CORS Anywhere 這套工具。

    使用方法非常簡單,假設使用者原本要存取的 API Domain 為:

    https://domain.com
    

    我們只要在該域名前面加上 CORS Anywhere 服務的域名即可,像是:

    https://cors-anywhere.herokuapp.com/https://domain.com
    

    此外, CORS Anywhere 也是開源專案,這代表只要你有興趣,可以自己建立一個服務。

    詳細方法請參閱 Github Repo

我是後端、全端開發者

如果使用者本身就有對後端程式修改的權限,那問題就變的很簡單了,以 Oak 所建立的 Web API 為例,我們將目光轉移到 app.ts :

import { Application, Router } from "https://deno.land/x/oak/mod.ts";
import { UserRoutes } from "./routers/Route.ts";

const app = new Application();
const router = new Router();
const userRoutes = UserRoutes(router);

app.use(userRoutes.routes());
app.use(userRoutes.allowedMethods());

await app.listen("127.0.0.1:3001");
console.log("? Deno start !");

筆者在 Github 上找到了一套名為 cors 的第三方套件,它的介紹開門見山、十分易懂:

CORS is a Deno.js module for providing a Oak/Opine/Abc/Attain/Mith middleware that can be used to enable CORS with various options.

-- cors

使用方法很簡單,主要分為兩步驟:

  1. 引用套件

    import { oakCors } from "https://deno.land/x/cors/mod.ts";
    
  2. 在 app 實例化後做處理:

    const app = new Application();
    app.use(oakCors()); // Enable CORS for All Routes
    app.use(router.routes());
    

完成後,我們的 Web API 會變成這樣:

import { Application, Router } from "https://deno.land/x/oak/mod.ts";
import { UserRoutes } from "./routers/Route.ts";
import { oakCors } from "https://deno.land/x/cors/mod.ts";

const app = new Application();
const router = new Router();
const userRoutes = UserRoutes(router);
app.use(oakCors()); // Enable CORS for All Routes
app.use(userRoutes.routes());
app.use(userRoutes.allowedMethods());

await app.listen("127.0.0.1:3001");
console.log("? Deno start !");

萬事俱備,就欠測試!

在處理完 Web API 以後,我們可以使用 Postman 這款好用的工具對 Web API 做測試,由於該工具的教學筆者已經在去年的鐵人賽就提到,還請容許大家讓我放個連結到延伸閱讀就好 QQ

總結

本篇沒有意外的話是本系列的最後一篇技術文章,如果喜歡我的文章歡迎按下訂閱!!

等等就可以來發心得文啦 XD

延伸閱讀

同樣的事情在不同人眼中可能會有不同的見解、看法。

在讀完本篇以後,筆者也強烈建議大家去看看以下文章,或許會對型別、變數宣告...等觀念有更深層的看法唷!


上一篇
強型闖入DenoLand[33] - Web API 正式完成!
下一篇
強型闖入DenoLand[35] - 完賽心得
系列文
強型闖入DenoLand37
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言