生产环境CORS白名单必须动态匹配Origin请求头并原样回写,禁用*、正则或逗号分隔列表;需校验credentials、处理OPTIONS预检、按环境隔离配置。

生产环境里配 CORS 白名单,核心就一条:不写 *,也不写正则或逗号分隔的域名列表——这些在浏览器标准里都不合法,只会让配置失效或埋下安全漏洞。
白名单必须动态匹配 Origin 请求头
浏览器在跨域请求中会自动带上 Origin 请求头(例如 https://app.company.com),服务端要做的不是硬编码多个值,而是读取这个头、比对预设的允许列表,再把**完全一致的 Origin 值**原样回写到 Access-Control-Allow-Origin 响应头中。
- ✅ 正确做法:检查
req.headers.origin是否在白名单集合里,是则设置res.header('Access-Control-Allow-Origin', origin) - ❌ 错误做法:
res.header('Access-Control-Allow-Origin', 'https://a.com, https://b.com')或res.header('Access-Control-Allow-Origin', '*.company.com')—— 浏览器直接拒绝 - ⚠️ 注意:如果前端带了 Cookie 或认证头(
credentials: true),Access-Control-Allow-Origin就不能用*,必须是具体域名
区分环境,禁止开发配置流入生产
本地调试时常用 http://localhost:3000 或 http://127.0.0.1:5173,但这些绝对不能出现在生产白名单里。建议用配置文件或环境变量管理:
- 开发环境:
ALLOWED_ORIGINS=["http://localhost:3000", "http://127.0.0.1:5173"] - 测试环境:
ALLOWED_ORIGINS=["https://test-app.company.com"] - 生产环境:
ALLOWED_ORIGINS=["https://app.company.com", "https://admin.company.com"] - 代码中统一读取
process.env.ALLOWED_ORIGINS并解析为数组,再做字符串比对
必须处理 OPTIONS 预检请求
当请求含自定义头、非简单方法(如 PUT/DELETE)或 JSON body 时,浏览器会先发一个 OPTIONS 请求探路。如果后端没响应这个请求,或者响应里缺 CORS 头,整个请求就卡住,控制台报错 “CORS request did not succeed”。
立即学习“Java免费学习笔记(深入)”;
- 确保所有路由(或全局中间件)都拦截
OPTIONS方法 - 对
OPTIONS响应至少包含:Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers - 不需要返回业务数据,
res.status(204).end()即可
配合 credentials 和 Cookie 的细节
如果前端设置了 fetch(..., { credentials: 'include' }),后端不仅要指定具体域名,还要显式开启凭据支持:
-
Access-Control-Allow-Credentials: true必须存在 -
Access-Control-Allow-Origin不能是*,只能是单个明确域名(如https://app.company.com) - 同时建议设置
Access-Control-Allow-Headers包含Authorization、Content-Type等实际用到的头


















