强型闯入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[35] - 完赛心得

Day14 NodeJS-NPM I

终於进入NodeJS中最为人知的套件管理系统NPM了,不讳言的当初对NodeJS一知半解的我对於No...

认识 React Hooks 之二

今天是延续昨天的 Hooks 探索,要学习的是 useReducer 、useCallback、us...

Day 4: 人工智慧在音乐领域的应用 (AI发展史与简介 - 第一次寒冬)

到底什麽是AI? 我想大部份的人应该都对AI/人工智慧/人工智能这些字眼不陌生,尤其是在AlphaG...

Day 14 - Arrow Function Expression & this

this 在 JavaScript 里,this 指向 window,在 function 中, t...

【Day4】原形设计之一

虽然 iOS的 StoryBoard已经够像原形设计的流程了,但是我想还是 有必要先进行类似的原形设...