CORS 中设置 credentials 为 true 为什么还是报错?

诺一(打工版) 阅读 26

我在前端用 fetch 请求后端接口,需要携带 cookie,所以加了 credentials: 'include'。后端也设置了 Access-Control-Allow-Credentials: true,但浏览器还是报 CORS 错误,说不能同时设置 credentials 和通配符 origin。

我后端是用 Express 写的,现在允许的 origin 是 *,难道这个不行?试过改成具体域名,但开发环境和生产环境域名不一样,总不能硬编码吧?

fetch('https://api.example.com/login', {
  method: 'POST',
  credentials: 'include',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ user: 'test' })
})

后端目前这样设置:

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Credentials', 'true');
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  next();
});
我来解答 赞 3 收藏
二维码
手机扫码查看
2 条解答
萌新.珍珍
问题很明确了,CORS 规范就是这样规定的:credentials 为 true 时,origin 不能用通配符 *,必须指定具体域名。

动态获取 origin 的方式很简单,改成下面这样就行:

app.use((req, res, next) => {
const origin = req.headers.origin;
res.header('Access-Control-Allow-Origin', origin);
res.header('Access-Control-Allow-Credentials', 'true');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();});
这样浏览器发请求时带什么 origin,就反射回去什么 origin。

不过直接反射所有 origin 有安全风险,生产环境最好还是限制一下。可以搞个白名单:

<pre class="pure-highlightjs line-numbers"><code class="language-javascript">const allowedOrigins = [
'http://localhost:3000',
'http://localhost:8080',
'https://your-prod-domain.com'
];

app.use((req, res, next) => {
const origin = req.headers.origin;
if (allowedOrigins.includes(origin)) {
res.header('Access-Control-Allow-Origin', origin);
res.header('Access-Control-Allow-Credentials', 'true');
}
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
});


开发环境和生产环境的域名不一致这个问题,可以把允许的域名列表放到环境变量里,或者从配置文件读取,生产环境配生产域名,开发环境配本地地址,这样就不用硬编码了。
点赞
2026-03-19 13:02
闲人天朝
这个问题我遇到过无数次,简直是 CORS 坑里的常客。

浏览器安全策略规定,当请求携带 credentials(cookie、authorization header 等)时,Access-Control-Allow-Origin 绝对不能用 * 通配符,必须返回具体的域名。这是硬性规则,没得商量。

解决办法就是动态获取请求方的 origin,然后白名单校验后再返回。你后端代码改成这样:

const allowedOrigins = [
'http://localhost:3000',
'http://localhost:8080',
'https://www.example.com',
'https://example.com'
];

app.use((req, res, next) => {
const origin = req.headers.origin;

if (allowedOrigins.includes(origin)) {
res.header('Access-Control-Allow-Origin', origin);
}

res.header('Access-Control-Allow-Credentials', 'true');
res.header('Access-Control-Allow-Headers', 'Content-Type');

// 处理预检请求
if (req.method === 'OPTIONS') {
res.sendStatus(200);
} else {
next();
}
});


几个关键点说一下:

第一,req.headers.origin 能拿到发起请求的域名,白名单匹配上再返回,这样开发环境和生产环境都能搞定。

第二,Access-Control-Allow-Origin 返回的值必须是请求头里的 origin 字符串,不能是多个域名拼接,也不能是数组格式。

第三,别忘了处理 OPTIONS 预检请求,不然复杂请求会卡住。

前端这块你写的是对的,credentials: 'include' 没问题。另外建议用 cors 这个中间件,比自己手写靠谱:

const cors = require('cors');

const corsOptions = {
origin: function (origin, callback) {
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
credentials: true
};

app.use(cors(corsOptions));


这样维护起来清晰多了,不用每次都手动写一堆 header。
点赞 2
2026-02-28 22:13