核心解决方案:跨域携带 Cookie 失败通常是因为 CORS 配置不完整。必须同时修改前端请求配置和服务端响应头,且 Access-Control-Allow-Origin 不能为星号 *。
- 前端:请求中显式开启
withCredentials或credentials: include - 后端:响应头指定具体域名,设置
Access-Control-Allow-Credentials: true - 验证:浏览器开发者工具 Network 面板确认响应头生效
前端请求配置
浏览器默认跨域请求不携带 Cookie,需在代码中显式声明。以下是常见请求库的配置方式:
1. Fetch API
fetch("https://api.example.com/data", {
method: "GET",
credentials: "include", // 关键配置:允许携带 Cookie
headers: {
"Content-Type": "application/json"
}
})
.then(response => response.json())
.catch(error => console.error("Error:", error));
2. Axios
// 全局配置
axios.defaults.withCredentials = true;
// 或单次请求配置
axios.get("https://api.example.com/data", {
withCredentials: true // 关键配置
});
后端服务配置
服务端需明确允许特定源携带凭证。直接使用 * 会导致浏览器拒绝携带 Cookie。
1. Node.js (Express + cors 中间件)
推荐使用 cors 中间件,避免手动拼接 Header 出错。注意 Origin 需校验白名单,不要直接反射请求头。
const cors = require("cors");
const express = require("express");
const app = express();
const allowedOrigins = ["https://your-frontend.com", "https://www.your-frontend.com"];
app.use(cors({
origin: function (origin, callback) {
// 安全校验:仅在白名单内允许,或允许无 origin (如 Postman/本地)
if (!origin || allowedOrigins.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(new Error("Not allowed by CORS"));
}
},
credentials: true, // 允许携带凭证
methods: ["GET", "POST", "OPTIONS"],
allowedHeaders: ["Content-Type", "Authorization"]
}));
app.listen(3000);
2. 手动设置响应头 (通用逻辑)
若不使用中间件,需确保 OPTIONS 预检请求也返回正确 Header。
// 伪代码示例
response.setHeader("Access-Control-Allow-Origin", "https://your-frontend.com");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
if (request.method === "OPTIONS") {
return response.send(204); // 预检请求直接返回
}
Nginx 反向代理配置
若在 Nginx 层处理 CORS,需注意 add_header 默认只在 200/204/301/302 状态码生效,建议添加 always 参数,并单独处理 OPTIONS 请求。
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://backend_server;
# 指定具体域名,禁止使用 *
add_header Access-Control-Allow-Origin "https://your-frontend.com" always;
add_header Access-Control-Allow-Credentials true always;
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
# 处理预检请求
if ($request_method = "OPTIONS") {
add_header Access-Control-Allow-Origin "https://your-frontend.com" always;
add_header Access-Control-Allow-Credentials true always;
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
return 204;
}
}
}
验证与排查
配置完成后,按以下步骤验证是否生效:
- 打开开发者工具:浏览器按 F12,进入 Network 面板。
- 触发请求:刷新页面或点击按钮触发跨域请求。
- 检查预检请求:查看是否有
OPTIONS请求,状态码应为 204 或 200。 - 检查响应头:点击正式请求,查看 Response Headers 是否包含:
Access-Control-Allow-Credentials: trueAccess-Control-Allow-Origin: https://your-frontend.com(必须与当前页面域名一致)
- 检查 Cookie:确认请求头 Request Headers 中是否包含
Cookie字段。
常见坑与注意事项
- Origin 不能为星号:当
Access-Control-Allow-Credentials为true时,Access-Control-Allow-Origin严禁设置为*,否则浏览器会拦截。 - Cookie SameSite 属性:跨域场景下,Cookie 的
SameSite属性需设置为None,且必须配合Secure属性(即必须在 HTTPS 环境下)。 - 动态 Origin 安全风险:不要直接将请求头中的
Origin反射回响应头,应维护一个白名单进行匹配,防止开放授权漏洞。 - 缓存问题:浏览器可能缓存了错误的 CORS 响应头。验证时尝试硬刷新 (Ctrl+F5) 或清除缓存,必要时在 Nginx 中关闭 OPTIONS 缓存。
- 端口一致性问题:域名相同但端口不同(如 80 与 8080)也属于跨域,需同样配置 CORS。