
当 FastAPI 后端成功设置 Cookie(响应含 Set-Cookie 头),但前端 Fetch 请求未自动携带该 Cookie 时,根本原因常是协议、域名或端口不一致导致的跨域限制——例如后端运行在 http://127.0.0.1:8000 而前端页面加载自 http://localhost:3000,二者被浏览器视为不同源,Cookie 默认被拒绝发送。
当 fastapi 后端成功设置 cookie(响应含 `set-cookie` 头),但前端 fetch 请求未自动携带该 cookie 时,根本原因常是协议、域名或端口不一致导致的跨域限制——例如后端运行在 `http://127.0.0.1:8000` 而前端页面加载自 `http://localhost:3000`,二者被浏览器视为不同源,cookie 默认被拒绝发送。
在构建多步骤注册流程(如分步收集用户名、邮箱验证码、个人信息)时,依赖 Cookie 在客户端维持临时会话状态是一种常见且轻量的设计。然而,即便后端正确返回了 Set-Cookie 响应头(可通过浏览器开发者工具的 Network 面板确认),前端仍可能无法在后续请求中自动附带该 Cookie——这并非代码逻辑错误,而是浏览器同源策略(Same-Origin Policy)与 Cookie 作用域(Domain/Path)严格校验的结果。
关键原因:localhost 与 127.0.0.1 并非同源
虽然 localhost 和 127.0.0.1 在网络层面指向同一台机器,但浏览器将其视为两个完全不同的域名(RFC 6265 明确规定:localhost 是一个特殊主机名,不等价于任何 IP 地址)。因此:
- 若前端页面 URL 为 http://localhost:3000/,而后端 API 地址为 http://127.0.0.1:8000/register/step2,
- 即使响应中设置了 Set-Cookie: session_id=abc123; Path=/; HttpOnly,
- 浏览器也不会将该 Cookie 关联到 localhost 源,更不会在后续对 127.0.0.1 的请求中自动发送它。
正确配置方案
✅ 方案一:统一使用 localhost(推荐)
- 将 FastAPI 启动地址改为 localhost:
uvicorn main:app --host localhost --port 8000
- 前端请求 URL 改为 http://localhost:8000/register/step2;
- 确保 credentials: 'include' 已设置(你已在代码中正确启用,这是必要前提)。
✅ 方案二:统一使用 127.0.0.1
- 前端 HTML 页面通过 http://127.0.0.1:3000/ 访问(而非 localhost);
- 后端保持 127.0.0.1:8000;
- 注意:部分开发服务器(如 Vite、Webpack Dev Server)默认仅绑定 localhost,需显式配置 host: '127.0.0.1'。
⚠️ 补充注意事项
- credentials: 'include' 必须存在:你已正确添加,缺此配置 Fetch 绝不会发送 Cookie;
- 避免混合协议:http://localhost 与 https://localhost 视为不同源;
- 检查 Cookie 属性:若后端设置了 SameSite=Strict 或 SameSite=Lax(FastAPI 默认行为),跨站上下文可能阻止发送;多步注册属同站操作,建议显式设为 SameSite=None 仅当配合 Secure=True(HTTPS)时才安全;开发环境可暂用 SameSite=Lax(默认)或 SameSite=None + Secure=False(仅限 http://localhost,现代浏览器可能拒绝,故优先统一域名);
- 验证 Cookie 是否存入:打开浏览器 DevTools → Application → Cookies,确认目标域名(如 localhost)下存在对应 Cookie。
示例:修正后的前端请求(确保同源)
// ✅ 正确:前后端均使用 localhost
fetch("http://localhost:8000/register/step2", {
method: "POST",
headers: { "Content-Type": "application/json" },
credentials: "include", // 必须保留
body: JSON.stringify({ email_code: code })
})
.then(res => res.json())
.then(data => {
if (data.status === "success") this.step3();
else console.error(data.message);
});
总结
Cookie 的“消失”往往不是传输失败,而是被浏览器静默拦截。排查顺序应为:
- 确认是否同源(协议 + 域名 + 端口完全一致);
- 检查 credentials: 'include' 是否设置;
- 查看 Network 面板中响应头是否有 Set-Cookie;
- 在 Application → Cookies 中确认 Cookie 是否写入对应域名;
- 审视 SameSite 和 Secure 属性是否与当前环境兼容。
统一使用 localhost 是最简单可靠的开发解决方案,无需修改后端逻辑或引入 CORS 复杂配置。











