koa2-cors設置容許指定單個域名、多個域名、全部域名跨域javascript
當一個資源從與該資源自己所在的服務器不一樣的域、協議或端口請求一個資源時,資源會發起一個跨域.html
CORS
跨域資源共享cross origin resource sharing
(CORS,跨域資源共享
) 是一種機制,它使用額外的HTTP
頭來告訴瀏覽器 讓運行在一個 origin
(domain
)上的Web
應用被准許訪問來自不一樣源服務器上的指定的資源。前端
cors
配置[koa2]const cors = require('koa2-cors');
app.use(cors());
複製代碼
app.use(
cors({
origin: function(ctx) { //設置容許來自指定域名請求
return 'http://localhost:8080'; //只容許http://localhost:8080這個域名的請求
},
maxAge: 5, //指定本次預檢請求的有效期,單位爲秒。
credentials: true, //是否容許發送Cookie
allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], //設置所容許的HTTP請求方法
allowHeaders: ['Content-Type', 'Authorization', 'Accept'], //設置服務器支持的全部頭信息字段
exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'] //設置獲取其餘自定義字段
})
);
複製代碼
app.use(
cors({
origin: function(ctx) { //設置容許來自指定域名請求
const whiteList = ['http://weipxiu.com','http://localhost:8081']; //可跨域白名單
let url = ctx.header.referer.substr(0,ctx.header.referer.length - 1);
if(whiteList.includes(url)){
return url //注意,這裏域名末尾不能帶/,不然不成功,因此在以前我把/經過substr幹掉了
}
return 'http://localhost::3000' //默認容許本地請求3000端口可跨域
},
maxAge: 5, //指定本次預檢請求的有效期,單位爲秒。
credentials: true, //是否容許發送Cookie
allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], //設置所容許的HTTP請求方法
allowHeaders: ['Content-Type', 'Authorization', 'Accept'], //設置服務器支持的全部頭信息字段
exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'] //設置獲取其餘自定義字段
})
);
複製代碼
在實際項目開發中,遇到這樣一個問題:在用戶登陸成功後爲用戶設置cookie
,當用戶再次訪問該網頁時直接從cookie
中獲取用戶信息。在項目中,我遇到的問題是,沒法從cookie
中獲取到用戶信息,獲取到的值是undefined
java
cookie
router.post('/smslogin', async(ctx,next) => {
// 1. 獲取數據
const qqEmail = ctx.request.body.qqEmail;
const pin = ctx.request.body.pin;
console.log(sms)
console.log(qqEmail,pin)
// // 2. 驗證驗證碼是否正確
if (pin != sms) {
ctx.body={err_code: 0, message: '驗證碼不正確!'};
sms = ''
return;
}
// 3. 查詢數據
let sqlStr = `SELECT * FROM users WHERE qqEmail = '${qqEmail}'`;
let res = await query(sqlStr)
if(res[0]){
ctx.cookies.set('userId', res[0].userId, {
domain: 'localhost', // 寫cookie所在的域名
path: '/', // 寫cookie所在的路徑
maxAge: 2 * 60 * 60 * 1000, // cookie有效時長
expires: new Date('2018-02-08'), // cookie失效時間
httpOnly: false, // 是否只用於http請求中獲取
overwrite: false // 是否容許重寫
})
}else{
ctx.body={err_code:200,message:'請註冊後登陸!'}
}
});
複製代碼
cookie
中的數據router.get('/userinfo',async(ctx,next) => {
// 1.0 獲取參數
let userId = ctx.cookies.get('userId') // 這裏獲取參數失敗
let res = await query(`SELECT * FROM users WHERE id = '${userId}'`)
delete res[0].password
ctx.body={
success_code:200,
message:res[0]
}
});
複製代碼
在同域的狀況下,咱們發送請求會默認攜帶當前域下的cookie
,可是在跨域的狀況下,默認是不會攜帶請求域下的cookie
的,好比http://domain-a.com
站點發送一個 http://api.domain-b.com/get
的請求,默認是不會攜帶 api.domain-b.com
域下的 cookie
.ios
在項目中,狀況是這樣的localhost:8080
站點取發送localhost:3000
的請求,二者端口不同,構成跨域,跨域默認是不會攜帶 localhost:3000
域下的 cookie
.sql
要解決這個問題,咱們就要讓這個跨域請求能夠攜帶上cookie
,作法很簡單:axios
在前端我是使用axios發起網絡請求後端
axios.defaults.withCredentials = true
複製代碼
在後端,咱們也要否容許瀏覽器攜帶cookie
訪問進行設置,也就是說咱們要將響應頭的credentials
設置爲true
api
credentials: true, //是否容許發送Cookie
複製代碼
此外,咱們還要對cors
進行配置。咱們不能容許全部域名進行跨域訪問:跨域
也就是說,咱們對cors
不能這樣配置.
const cors = require('koa2-cors');
app.use(cors());
複製代碼
比較推薦的作法是
設置多個域名可跨域
app.use(
cors({
origin: function(ctx) { //設置容許來自指定域名請求
const whiteList = ['http://weipxiu.com','http://localhost:8081']; //可跨域白名單
let url = ctx.header.referer.substr(0,ctx.header.referer.length - 1);
if(whiteList.includes(url)){
return url //注意,這裏域名末尾不能帶/,不然不成功,因此在以前我把/經過substr幹掉了
}
return 'http://localhost::3000' //默認容許本地請求3000端口可跨域
},
maxAge: 5, //指定本次預檢請求的有效期,單位爲秒。
credentials: true, //是否容許發送Cookie
allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], //設置所容許的HTTP請求方法
allowHeaders: ['Content-Type', 'Authorization', 'Accept'], //設置服務器支持的全部頭信息字段
exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'] //設置獲取其餘自定義字段
})
);
複製代碼
至此,問題已經解決。
雖然問題已經解決了,咱們還應該思考一下,在上面的狀況中,爲何不能將cors
設置爲容許所有域名跨域?
如下是我的理解: 從安全方面考慮,將cors
設置爲容許所有域名跨域可讓咱們在後端獲取到cookie
的值,後端處理是沒有問題的,可是服務器考慮到安全性會攔截Access-Control-Allow-Origin: *
的響應。