一、解決瀏覽器跨域問題的方法有很多種
- 通過後端設定 http Access-Control-* 相關響應頭
- 通過 Jsonp
- 通過 nginx 反向代理
關於這三種解決跨域方法的介紹可以看我的另外一篇文章: 如何解決前端跨域問題
本文主要講基於 nodejs koa2 實現第一種跨域方案,並設計成 koa2 中介軟體
二、跨域中介軟體實現的功能
- 支援跨域 cookie
- 支援指定的跨域 http 請求頭,比如 accesstoken 等
- 對預檢結果進行快取,快取時間設定為1天(即86400秒)
- 當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 程式碼
參考文件: