CORS 通过控制 Access-Control-Allow-Origin 控制哪些域名可以共享资源,取值如下

Access-Control-Allow-Origin: <origin> | *

其中 * 代表所有域名,origin 代表指定特定域名

但是 * 作为通配符来说,直接变成对所有域名公开,非常的不安全。那如何设置特定的多个域名?

根据我们惯性思维,可能会想出如下的方法进行多域名配置:

//1、通过逗号分隔各个域名【错误!】

res.header('Access-Control-Allow-Origin','http://localhost:3000,http://localhost:3001');

//2、在头部添加重复字段【错误!】

res.header('Access-Control-Allow-Origin','http://localhost:3000');
res.header('Access-Control-Allow-Origin','http://localhost:3001');

但这些都是错误的!会导致所有的origin都对跨域请求无效!

正确的做法,写出代码检测Origin,给Access-Control-Allow-Origin进行动态配置,代码如下:

// 获取 Origin 请求头
const requestOrigin = ctx.get('Origin');

// 如果没有,则跳过;或者不符合白名单条件
if (!requestOrigin || ...) {
  return await next();
}

// 设置响应头
ctx.set('Access-Control-Allow-Origin', requestOrigin)

但是特别注意:缓存/CDN对响应头字段的影响,可能会导致上述的错误情况2

因此,响应现支持字段Vary,其可以对报文中某个字段的缓存进行控制

Vary: *  所有字段都不进行缓存

Vary:<header1> , <header2>... 某些字段进行缓存

因此我们可以设置Vary:Origin,让服务器不调用缓存中的Origin字段,每次都自动检测,代码如下:

// 获取 Origin 请求头
const requestOrigin = ctx.get('Origin');

ctx.set('Vary', 'Origin')

// 如果没有,则跳过;或者不符合白名单条件
if (!requestOrigin || ...) {
  return await next();
}

// 设置响应头
ctx.set('Access-Control-Allow-Origin', requestOrigin)

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐