You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js无法接收Django返回的Cookie问题求助

核心原因

跨域请求中,前端fetch默认不处理Cookie,同时Django的CORS配置不符合带Cookie的跨域要求。

解决方案步骤

1. 修改Next.js的fetch请求配置

在登录请求中添加credentials: "include",并指定Content-Type头(匹配JSON格式的请求体):

async function logIn(e: FormEvent) {
  e.preventDefault();

  const body = JSON.stringify({ email: email, password: password });

  const res = await fetch(process.env.API_URL + "login/", {
    method: "POST",
    body: body,
    credentials: "include", // 关键:允许跨域接收Cookie
    headers: {
      "Content-Type": "application/json", // 明确告诉后端请求体格式
    },
  });

  if (res.status === 200) {
    router.push("/");
  }
}

2. 修正Django后端的CORS配置与Cookie设置

关键修改点:

  • 不能使用Access-Control-Allow-Origin: *,必须指定具体前端域名(如http://localhost:3000)
  • 添加Access-Control-Allow-Credentials: true头,允许跨域携带Cookie
  • 密码验证必须用Django内置的check_password方法(直接比较明文密码极度不安全)
  • 调整SameSite属性为Lax(Strict会在跨域跳转时阻止Cookie发送)

修改后的Django视图代码:

import json
from django.http import JsonResponse
from django.contrib.auth.models import User
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def login(req):
    # 处理OPTIONS预检请求(跨域请求会先发送OPTIONS)
    if req.method == "OPTIONS":
        res = JsonResponse({})
        res["Access-Control-Allow-Origin"] = "http://localhost:3000"
        res["Access-Control-Allow-Credentials"] = "true"
        res["Access-Control-Allow-Methods"] = "POST, OPTIONS"
        res["Access-Control-Allow-Headers"] = "Content-Type"
        return res

    body = json.loads(req.body.decode("utf-8"))
    res = None

    if User.objects.filter(email=body["email"]).exists():
        user = User.objects.get(email=body["email"])
        # 使用Django内置方法验证哈希密码(Django默认存储哈希后的密码)
        if user.check_password(body["password"]):
            res = JsonResponse({"success": True})
            res.set_cookie(
                "AuthToken", 
                json.dumps({"id": user.id}),
                max_age=60 * 60 * 24,
                httponly=False,
                samesite="Lax",
                secure=False, # 生产环境HTTPS下改为True
            )
        else:
            res = JsonResponse({"success": False}, status=401)
    else:
        res = JsonResponse({"success": False}, status=404)

    res["Access-Control-Allow-Origin"] = "http://localhost:3000"
    res["Access-Control-Allow-Credentials"] = "true"
    print(res.cookies)
    return res

3. 推荐优化:使用django-cors-headers管理CORS

手动设置CORS头容易遗漏预检请求,推荐使用官方维护的django-cors-headers库:

  1. 安装:pip install django-cors-headers
  2. 在settings.py中配置:
INSTALLED_APPS = [
    # ...
    'corsheaders',
]

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware', # 放在中间件列表最前面
    'django.middleware.common.CommonMiddleware',
    # ...
]

CORS_ALLOWED_ORIGINS = [
    "http://localhost:3000", # 替换为你的前端实际域名/端口
]

CORS_ALLOW_CREDENTIALS = True

额外注意事项

  • 永远不要直接存储或比较明文密码,Django默认对密码进行哈希处理,必须用check_password验证
  • 生产环境中,Cookie的secure属性要设为True(仅通过HTTPS传输),httponly建议设为True(防止XSS攻击窃取Cookie)
  • 测试时确保前端和后端的域名、端口完全匹配,避免跨域配置不匹配

内容的提问来源于stack exchange,提问作者TheStupid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 11:25:21