CORS 中设置 credentials 为 true 为什么还是报错?
我在前端用 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();
});
*,必须指定具体域名。动态获取 origin 的方式很简单,改成下面这样就行:
浏览器安全策略规定,当请求携带 credentials(cookie、authorization header 等)时,
Access-Control-Allow-Origin绝对不能用*通配符,必须返回具体的域名。这是硬性规则,没得商量。解决办法就是动态获取请求方的 origin,然后白名单校验后再返回。你后端代码改成这样:
几个关键点说一下:
第一,
req.headers.origin能拿到发起请求的域名,白名单匹配上再返回,这样开发环境和生产环境都能搞定。第二,
Access-Control-Allow-Origin返回的值必须是请求头里的 origin 字符串,不能是多个域名拼接,也不能是数组格式。第三,别忘了处理 OPTIONS 预检请求,不然复杂请求会卡住。
前端这块你写的是对的,
credentials: 'include'没问题。另外建议用 cors 这个中间件,比自己手写靠谱:这样维护起来清晰多了,不用每次都手动写一堆 header。