一囚霸、解決瀏覽器跨域問(wèn)題的方法有很多種
- 通過(guò)后端設(shè)置 http Access-Control-* 相關(guān)響應(yīng)頭
- 通過(guò) Jsonp
- 通過(guò) nginx 反向代理
關(guān)于這三種解決跨域方法的介紹可以看我的另外一篇文章: 如何解決前端跨域問(wèn)題
本文主要講基于 nodejs koa2 實(shí)現(xiàn)第一種跨域方案,并設(shè)計(jì)成 koa2 中間件
二、跨域中間件實(shí)現(xiàn)的功能
- 支持跨域 cookie
- 支持指定的跨域 http 請(qǐng)求頭拿撩,比如 accesstoken 等
- 對(duì)預(yù)檢結(jié)果進(jìn)行緩存,緩存時(shí)間設(shè)置為1天(即86400秒)
- 當(dāng)http method 為 OPTIONS時(shí)屯仗,為預(yù)檢時(shí)近刘,此時(shí)直接返回空響應(yīng)體,對(duì)應(yīng)的 http 狀態(tài)碼為 204
三、koa-cors 中間件代碼
koa-cors.js
const URL = require('url');
/**
* 關(guān)鍵點(diǎn):
* 1联逻、如果需要支持 cookies,
* Access-Control-Allow-Origin 不能設(shè)置為 *,
* 并且 Access-Control-Allow-Credentials 需要設(shè)置為 true
* (注意前端請(qǐng)求需要設(shè)置 withCredentials = true)
* 2、當(dāng) method = OPTIONS 時(shí), 屬于預(yù)檢(復(fù)雜請(qǐng)求), 當(dāng)為預(yù)檢時(shí), 可以直接返回空響應(yīng)體, 對(duì)應(yīng)的 http 狀態(tài)碼為 204
* 3检痰、通過(guò) Access-Control-Max-Age 可以設(shè)置預(yù)檢結(jié)果的緩存, 單位(秒)
* 4包归、通過(guò) Access-Control-Allow-Headers 設(shè)置需要支持的跨域請(qǐng)求頭
* 5、通過(guò) Access-Control-Allow-Methods 設(shè)置需要支持的跨域請(qǐng)求方法
*/
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') {
// 如果請(qǐng)求類(lèi)型為非預(yù)檢請(qǐng)求铅歼,則進(jìn)入下一個(gè)中間件(包括路由中間件等)
await next();
} else {
// 當(dāng)為預(yù)檢時(shí)公壤,直接返回204,代表空響應(yīng)體
ctx.body = '';
ctx.status = 204;
}
};
Access-Control-Allow-Origin:
Access-Control-Allow-Origin 可以設(shè)置為 *
通配符换可,也可以指定具體的地址比如:https://developer.mozilla.org
。
當(dāng)把 Access-Control-Allow-Origin 設(shè)置為 *
時(shí)厦幅,表示允許所有資源訪問(wèn)沾鳄,但是此時(shí)不支持帶 credentials 的請(qǐng)求,
因此為了實(shí)現(xiàn)允許所有資源訪問(wèn)且支持帶 credentials 的請(qǐng)求确憨,將其設(shè)置為 ${origin.protocol}//${origin.host}
(即動(dòng)態(tài)獲取訪問(wèn)者地址)
Access-Control-Allow-Headers
默認(rèn)支持 Accept译荞、Accept-Language、Content-Language休弃、Content-Type (只支持 application/x-www-form-urlencoded, multipart/form-data, or text/plain)吞歼。
如果請(qǐng)求頭需要添加自定義的 http header 比如 access_token ,那么需要將 access_token 添加進(jìn)數(shù)組中
Access-Control-Allow-Credentials
簡(jiǎn)單的理解就是支持 cookie
Access-Control-Max-Age
設(shè)置 OPTIONS 請(qǐng)求(預(yù)檢請(qǐng)求)的返回結(jié)果的緩存時(shí)間, 單位s
關(guān)于 OPTIONS 請(qǐng)求:
在非簡(jiǎn)單請(qǐng)求且跨域的情況下,瀏覽器會(huì)發(fā)起 options 預(yù)檢請(qǐng)求塔猾。
可以參考我的另一篇文章:關(guān)于瀏覽器預(yù)檢請(qǐng)求
四篙骡、使用方法
app.js
const cors = require('./middlewares/koa-cors');
app.use(cors); // 跨域
五、github 代碼
https://github.com/SimpleCodeCX/myCode/tree/master/nodejs/koa2/cors-demo
參考文檔: