基於nodejs koa2的解決跨域中介軟體設計

SimpleXD發表於2019-04-14

一、解決瀏覽器跨域問題的方法有很多種

  1. 通過後端設定 http Access-Control-* 相關響應頭
  2. 通過 Jsonp
  3. 通過 nginx 反向代理

關於這三種解決跨域方法的介紹可以看我的另外一篇文章: 如何解決前端跨域問題

本文主要講基於 nodejs koa2 實現第一種跨域方案,並設計成 koa2 中介軟體

二、跨域中介軟體實現的功能

  1. 支援跨域 cookie
  2. 支援指定的跨域 http 請求頭,比如 accesstoken 等
  3. 對預檢結果進行快取,快取時間設定為1天(即86400秒)
  4. 當http method 為 OPTIONS時,為預檢時,此時直接返回空響應體,對應的 http 狀態碼為 204

三、koa-cors 中介軟體程式碼

koa-cors.js

const URL = require('url');
/**
 * 關鍵點:
 * 1、如果需要支援 cookies,
 *    Access-Control-Allow-Origin 不能設定為 *,
 *    並且 Access-Control-Allow-Credentials 需要設定為 true
 *    (注意前端請求需要設定 withCredentials = true)
 * 2、當 method = OPTIONS 時, 屬於預檢(複雜請求), 當為預檢時, 可以直接返回空響應體, 對應的 http 狀態碼為 204
 * 3、通過 Access-Control-Max-Age 可以設定預檢結果的快取, 單位(秒)
 * 4、通過 Access-Control-Allow-Headers 設定需要支援的跨域請求頭
 * 5、通過 Access-Control-Allow-Methods 設定需要支援的跨域請求方法
 */
module.exports = async function (ctx, next) {
  const origin = URL.parse(ctx.get('origin') || ctx.get('referer') || '');
  if (origin.protocol && origin.host) {
    ctx.set('Access-Control-Allow-Origin', `${origin.protocol}//${origin.host}`);
    ctx.set('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, DELETE, PUT');
    ctx.set('Access-Control-Allow-Headers', 'X-Requested-With, User-Agent, Referer, Content-Type, Cache-Control,accesstoken');
    ctx.set('Access-Control-Max-Age', '86400');
    ctx.set('Access-Control-Allow-Credentials', 'true');
  }
  if (ctx.method !== 'OPTIONS') {
    // 如果請求型別為非預檢請求,則進入下一個中介軟體(包括路由中介軟體等)
    await next();
  } else {
    // 當為預檢時,直接返回204,代表空響應體
    ctx.body = '';
    ctx.status = 204;
  }
};
複製程式碼

Access-Control-Allow-Origin:

Access-Control-Allow-Origin 可以設定為 * 萬用字元,也可以指定具體的地址比如:https://developer.mozilla.org

當把 Access-Control-Allow-Origin 設定為 * 時,表示允許所有資源訪問,但是此時不支援帶 credentials 的請求,

因此為了實現允許所有資源訪問且支援帶 credentials 的請求,將其設定為 ${origin.protocol}//${origin.host}(即動態獲取訪問者地址)

Access-Control-Allow-Headers

預設支援 Accept、Accept-Language、Content-Language、Content-Type (只支援 application/x-www-form-urlencoded, multipart/form-data, or text/plain)。

如果請求頭需要新增自定義的 http header 比如 access_token ,那麼需要將 access_token 新增進陣列中

Access-Control-Allow-Credentials

簡單的理解就是支援 cookie

Access-Control-Max-Age

設定 OPTIONS 請求(預檢請求)的返回結果的快取時間, 單位s

關於 OPTIONS 請求: 在非簡單請求且跨域的情況下,瀏覽器會發起 options 預檢請求。 可以參考我的另一篇文章:關於瀏覽器預檢請求

四、使用方法

app.js

const cors = require('./middlewares/koa-cors');
app.use(cors); // 跨域
複製程式碼

五、github 程式碼

github.com/SimpleCodeC…

參考文件:

Access-Control-Allow-Headers

credentials

Access-Control-Allow-Credentials

Access-Control-Max-Age

相關文章