CORS 如果需要指定多个域名怎么办
Issue 欢迎在 Gtihub Issue 中回答此问题: Issue 364
Author 回答者: shfshanyue
CORS 通过控制 Access-Control-Allow-Origin 控制哪些域名可以共享资源,取值如下
Access-Control-Allow-Origin: <origin> | *其中 * 代表所有域名,origin 代表指定特定域名,那如何设置多个域名了?
此时需要通过代码实现,根据请求头中的 Origin 来设置响应头 Access-Control-Allow-Origin,那 Origin 又是什么东西?
请求头: Origin
并不是所有请求都会自动带上 Origin,在浏览器中带 Origin 的逻辑如下
- 如果存在跨域,则带上
Origin,值为当前域名 - 如果不存在跨域,则不带
Origin
逻辑理清楚后,关于服务器中对于 Access-Control-Allow-Origin 设置多域名的逻辑也很清晰了
- 如果请求头不带有
Origin,证明未跨域,则不作任何处理 - 如果请求头带有
Origin,证明跨域,根据Origin设置相应的Access-Control-Allow-Origin: <Origin>
使用伪代码实现如下:
// 获取 Origin 请求头
const requestOrigin = ctx.get("Origin");
// 如果没有,则跳过
if (!requestOrigin) {
return await next();
}
// 设置响应头
ctx.set("Access-Control-Allow-Origin", requestOrigin);Vary: Origin
此时可以给多个域名控制 CORS,但此时假设有两个域名访问 static.shanyue.tech 的跨域资源
foo.shanyue.tech,响应头中返回Access-Control-Allow-Origin: foo.shanyue.techbar.shanyue.tech,响应头中返回Access-Control-Allow-Origin: bar.shanyue.tech
看起来一切正常,但如果中间有缓存怎么办?
foo.shanyue.tech,响应头中返回Access-Control-Allow-Origin: foo.shanyue.tech,被 CDN 缓存bar.shanyue.tech,因由缓存,响应头中返回Access-Control-Allow-Origin: foo.shanyue.tech,跨域出现问题
此时,Vary: Origin 就上场了,代表为不同的 Origin 缓存不同的资源
总结 (简要答案)
CORS 如何指定多个域名?
根据请求头中的 Origin 来设置响应头 Access-Control-Allow-Origin,思路如下
- 总是设置
Vary: Origin,避免 CDN 缓存破坏 CORS 配置 - 如果请求头不带有
Origin,证明未跨域,则不作任何处理 - 如果请求头带有
Origin,证明浏览器访问跨域,根据Origin设置相应的Access-Control-Allow-Origin: <Origin>
使用伪代码实现如下
// 获取 Origin 请求头
const requestOrigin = ctx.get("Origin");
ctx.set("Vary", "Origin");
// 如果没有,则跳过
if (!requestOrigin) {
return await next();
}
// 设置响应头
ctx.set("Access-Control-Allow-Origin", requestOrigin);