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

Next.js请求Django服务器遭遇CSRF 403错误(已传Token仍报错)

问题描述

本地同时运行Django服务器与Next.js客户端,从Next.js向Django发送POST请求时,已传递CSRF Token但仍收到403 Forbidden (CSRF cookie not set.)错误。Postman/Insomnia调用同一API可正常工作,Next.js应用中请求失败。已排查CORS并修改Django的settings.py配置,问题依旧。

获取CSRF Token的API步骤正常,以下是Next.js请求代码:

const uploadFile = async () => {
  // Select file from input element or any other method
  const fileInput = document.getElementById('fileInput');
  const file = fileInput.files[0];

  const form = new FormData();
  form.append("image", file);

  const options = {
    method: 'POST',
    headers: {
      cookie: 'csrftoken=2V7dKpZXLN24pLDdDkub9GxM2ljzI0nI',
      'Content-Type': 'multipart/form-data; boundary=---011000010111000001101001',
      'X-CSRFToken': '2V7dKpZXLN24pLDdDkub9GxM2ljzI0nI'
    }
  };

  options.body = form;

  fetch('http://127.0.0.1:8000/getinfo', options)
    .then(response => response.json())
    .then(response => console.log(response))
    .catch(err => console.error(err));
};

Django项目settings.py配置:

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = [
    'mymedic.pythonanywhere.com',
    '127.0.0.1',
]


# Application definition

INSTALLED_APPS = [
    'backend.apps.BackendConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'corsheaders'
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    

    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',

    'django.middleware.common.CommonMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
CSRF_COOKIE_HTTPONLY=False
SESSION_COOKIE_SECURE=False
CSRF_COOKIE_SECURE=False
CORS_ALLOW_CREDENTIALS = True
# https://stackoverflow.com/questions/53215045/redirect-is-not-allowed-for-a-preflight-request
CORS_ALLOW_HEADERS = (
    'accept',
    'accept-encoding',
    'authorization',
    'content-type',
    'dnt',
    'origin',
    'user-agent',
    'x-csrftoken',
    'x-requested-with',
    'user',
    'apikey',
    'Referer',
    'credentials',
    'image,'
    'username',
)

CORS_ALLOWED_ORIGINS = [
    'http://localhost:3000',  # Add the origin of your Next.js application

]

CORS_ALLOW_ALL_ORIGINS = False  # Disable allowing all origins

CSRF_TRUSTED_ORIGINS = [
    'http://localhost:3000',
    'https://*.mydomain.com',
    'https://*.127.0.0.1'
]
问题分析
  1. 手动设置Cookie无效:浏览器会自动管理Cookie,跨域场景下手动硬编码的cookie头可能被浏览器拦截,无法被Django正确识别。
  2. Content-Type配置错误:使用FormData时,浏览器会自动生成带正确boundary的multipart/form-data请求头,手动指定的boundary与实际生成的不匹配,会导致请求解析异常,进而影响CSRF验证。
  3. CSRF_TRUSTED_ORIGINS配置不匹配:Next.js运行在http://localhost:3000,但配置中的https://*.127.0.0.1是HTTPS协议,与本地HTTP环境不兼容。
  4. CORS_ALLOW_HEADERS语法错误:'image,'末尾多了一个逗号,会导致头信息解析失败。
调试方法
  • 查看浏览器网络请求:打开开发者工具(F12)→Network标签,检查POST请求的Request Headers:
    • Cookie中是否包含csrftoken字段
    • X-CSRFToken头的值是否与Cookie中的一致
    • Request URL和Origin是否匹配CSRF_TRUSTED_ORIGINS配置
  • 检查Django日志:查看Django控制台输出的CSRF验证失败详情,日志会明确提示失败原因(如Cookie不存在、Token不匹配等)
  • 简化请求测试:先发送不带文件的普通POST请求,验证CSRF机制是否正常,再逐步添加FormData和文件上传逻辑
修改建议

1. 修正Next.js请求代码

去掉手动设置的cookie和Content-Type头,让浏览器自动处理,同时开启凭证携带:

const uploadFile = async () => {
  const fileInput = document.getElementById('fileInput');
  const file = fileInput.files[0];

  const form = new FormData();
  form.append("image", file);

  // 从浏览器Cookie中解析CSRF Token
  const csrfToken = document.cookie.split('; ').find(row => row.startsWith('csrftoken='))?.split('=')[1];

  const options = {
    method: 'POST',
    headers: {
      'X-CSRFToken': csrfToken
    },
    credentials: 'include' // 关键:携带Cookie等凭证
  };

  options.body = form;

  fetch('http://127.0.0.1:8000/getinfo', options)
    .then(response => response.json())
    .then(response => console.log(response))
    .catch(err => console.error(err));
};

注:如果解析Cookie麻烦,可安装js-cookie库,用Cookies.get('csrftoken')直接获取Token。

2. 修正Django settings.py配置

  • 调整CSRF_TRUSTED_ORIGINS,添加HTTP协议的本地地址:
CSRF_TRUSTED_ORIGINS = [
    'http://localhost:3000',
    'https://*.mydomain.com',
    'http://127.0.0.1'  # 改为HTTP协议,去掉不必要的通配符
]
  • 修正CORS_ALLOW_HEADERS中的语法错误:
CORS_ALLOW_HEADERS = (
    'accept',
    'accept-encoding',
    'authorization',
    'content-type',
    'dnt',
    'origin',
    'user-agent',
    'x-csrftoken',
    'x-requested-with',
    'user',
    'apikey',
    'Referer',
    'credentials',
    'image',  # 去掉末尾的逗号
    'username',
)
  • 保持Middleware顺序:确保CorsMiddleware在CommonMiddleware之前,当前配置已符合要求,不要随意调整。

3. 验证CSRF Token存储

在浏览器开发者工具→Application→Cookies→http://127.0.0.1:8000下,确认存在csrftoken字段,且值与请求头中的X-CSRFToken一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 13:30:54