问题: 我想验证跨域时 Cookie 能不能正常传过去,但遇到一堆坑!
坑点 1:伪跨域测试 (localhost 骗局) 问题: 前后端都用 localhost
,虽然端口不同 (比如 3000 和 4000),前后端都是同站点,都是 localhost
,sameSite: 'strict'
在这种场景不生效,因为他只限制,就是如果是不同站点的话,就不发 cookie,但是现在明显是同站点,都是 localhost
,cookie 照样发,测不出跨域问题!
解决: 狠心让前后端"分手"!前端用 http://localhost:3000
,后端用 http://127.0.0.1:4000
,现在前后端既跨域,又是不同站点。
坑点 2:Cookie 设置被浏览器无视 (secure + sameSite 强制 CP)
问题: 后端设置了 sameSite: 'none'
(允许跨域带 Cookie),但必须同时加 secure: true
(只允许 HTTPS)。不加这个,浏览器直接扔了你的 Cookie!
测试环境: 谷歌浏览器允许在设置了 secure: true
的情况下,测试环境使用 http 依旧可以发送 cookie(但是仅限当前会话,浏览器一刷新 cookie 就丢了)。
解决: 后端发 Cookie 必须锁死这对组合:
arduino
res.cookie('名字', '值', {
sameSite: 'none',
secure: true, // 这俩必须同时出现!
// ...其他配置
});
坑点 3:credentials: 'include'
credentials: 'include'
的作用:
- 浏览器携带相关 Cookie 给后端。
- 浏览器保存后端送来的 Cookie,也就是说你不设置这个东西,后端给的 Cookie 前端不会保存的。
解决:
arduino
await fetch(后端地址, {
method: 'GET', // 或其他
credentials: 'include' // 关键!意思是:我要存/带 Cookie!
});

坑点 4:Access-Control-Allow-Credentials
Access-Control-Allow-Credentials: true
的作用是:
允许浏览器携带 cookie,这个属性主要是告诉浏览器,你能不能带东西过来,如果我不允许,你还带,浏览器自己就会报 cors 错误。
解决:
arduino
// 你的手动 CORS 中间件里:
res.setHeader('Access-Control-Allow-Credentials', 'true'); // 必须加这行!
如果不设置这个属性:
你前端带东西过去,后端不允许你前端带东西,那前端就报错了。
最后给出验证代码:
xml
<!-- frontend/index.html -->
<!DOCTYPE html>
<html lang="">
<meta charset="utf-8"></meta>
<head>
<title>跨域Cookie演示</title>
</head>
<body>
<h1>跨域Cookie设置演示</h1>
<button id="requestBtn">发送跨域请求</button>
<script>
document.getElementById('requestBtn').addEventListener('click', async () => {
try {
const backendUrl = 'http://127.0.0.1:4000/api/cookie'
await fetch(`${backendUrl}/set`, {
method: 'GET',
credentials: 'include' // 保存后端送来的 cookie
})
await fetch(`${backendUrl}/get`, {
method: 'GET',
credentials: 'include' // 携带已有的 cookie 发送给后端
})
} catch (error) {
console.error('发生错误:', error)
}
})
</script>
</body>
</html>
javascript
const express = require('express')
const cookieParser = require('cookie-parser')
const app = express()
const BACKEND_PORT = 4000
// 关键中间件
app.use(cookieParser())
app.use(express.json())
// 手动CORS中间件 (替换cors库)
app.use((req, res, next) => {
// 1. 允许任意源访问
const origin = req.headers.origin
if (origin) {
res.setHeader('Access-Control-Allow-Origin', origin)
}
// 1.允许前端保存 cookie 2.允许前端传递 cookie
res.setHeader('Access-Control-Allow-Credentials', 'true')
next()
})
// Route 1: 设置Cookie
app.get('/api/cookie/set', (req, res) => {
// 关键Cookie设置 (注意属性)
res.cookie('custom_cookie', 'super_secret_value', {
secure: true, // 在 https 请求才会携带 cookie(sameSite: 'none',时 secure: true 要同时成立)
sameSite: 'none', // 必须:允许跨域访问
path: '/', // 整个网站可用
maxAge: 36000000 // 过期时间
})
res.send('Cookie已设置!检查浏览器控制台的Network标签')
})
// Route 2: 检查Cookie是否被发回
app.get('/api/cookie/get', (req, res) => {
console.log(req.cookies)
res.send(req.cookies)
})
app.listen(BACKEND_PORT, () => {
console.log(`
╔═════════════════════════════════════════╗
║ 后端服务运行中 ║
║ 地址: http://localhost:${BACKEND_PORT} ║
╚═════════════════════════════════════════╝
`)
})
总之,因为浏览器默认跨域是不会保存 cookie 的,总之为了跨域 cookie 不出问题,前端就要 credentials: 'include'
,后端就要 res.setHeader('Access-Control-Allow-Credentials', 'true')
。
当然这都是我在本地测试的环境,鬼知道谷歌浏览器的本地测试,还有其他不同浏览器有没有不同的差异,或者上线实际的生产环境,https环境,会不会有什么其他的问题,这都是有待测试的,有其他兄弟测试过,也可以跟我讲一讲。