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

为什么Axios无法设置CSRF Token请求头(Django+Next.js场景)

问题根因

  • 当csrftoken Cookie被设置为HTTP-only、或者前后端跨域时,浏览器禁止JS读取该Cookie的值,Axios即使配置了xsrf相关参数也无法自动提取Cookie值填充到X-CSRFToken请求头。
  • 未预先触发Django下发csrftoken Cookie的逻辑,Django默认仅在返回包含CSRF模板标签的页面、或者主动调用get_token方法时才会设置该Cookie。

方案1:同域部署场景(前后端域名/子域名一致)

  1. 先确认Django配置CSRF_COOKIE_HTTPONLY = False,确保JS可以读取csrftoken Cookie
  2. 手动读取Cookie值填充请求头,示例代码如下:
// 工具函数:提取指定Cookie
function getCookie(name) {
  let value = null;
  if (document.cookie && document.cookie !== '') {
    const cookies = document.cookie.split(';');
    for (const cookie of cookies) {
      const trimmed = cookie.trim();
      if (trimmed.startsWith(`${name}=`)) {
        value = decodeURIComponent(trimmed.slice(name.length + 1));
        break;
      }
    }
  }
  return value;
}

// 发起请求
axios
  .post(`${process.env.NEXT_PUBLIC_API_URL}/shops`, createShopFormData, {
    headers: {
      'X-CSRFToken': getCookie('csrftoken')
    },
    withCredentials: true,
  })
  .then((response) => console.log(response))
  .catch((error) => console.log(error.response?.data.message));

方案2:跨域部署场景(前后端域名完全不同)

第一步:Django侧配置

  1. 新增CSRF Token下发接口:
# views.py
from django.http import JsonResponse
from django.middleware.csrf import get_token

def get_csrf_token(request):
    return JsonResponse({"csrf_token": get_token(request)})
  1. 配置CORS和CSRF信任域名:
# settings.py
INSTALLED_APPS = [
    # ... 其他应用
    "corsheaders",
]

MIDDLEWARE = [
    # 放在最前面
    "corsheaders.middleware.CorsMiddleware",
    # ... 其他中间件
    "django.middleware.common.CommonMiddleware",
]

CORS_ALLOW_CREDENTIALS = True
# 替换为你的Next.js前端域名
CORS_ALLOWED_ORIGINS = ["http://localhost:3000"]
CSRF_TRUSTED_ORIGINS = ["http://localhost:3000"]
# 保持csrftoken非HTTP-only
CSRF_COOKIE_HTTPONLY = False

第二步:Next.js侧封装请求

建议统一封装Axios实例,全局处理CSRF头注入:

// utils/request.js
import axios from "axios";

const request = axios.create({
  baseURL: process.env.NEXT_PUBLIC_API_URL,
  withCredentials: true,
});

let cachedCsrfToken = null;

// 请求拦截器统一注入CSRF头
request.interceptors.request.use(async (config) => {
  // 仅非GET请求需要携带CSRF头
  if (config.method !== "get" && !cachedCsrfToken) {
    // 首次发起非GET请求前先获取CSRF Token
    const { data } = await request.get("/get-csrf-token/");
    cachedCsrfToken = data.csrf_token;
  }
  if (cachedCsrfToken) {
    config.headers["X-CSRFToken"] = cachedCsrfToken;
  }
  return config;
});

export default request;

后续业务直接调用封装好的实例即可:

import request from "@/utils/request";

request.post("/shops", createShopFormData)
  .then((response) => console.log(response))
  .catch((error) => console.log(error.response?.data.message));

注意事项

  • 如果你使用Next.js服务端组件发请求,无法直接读取浏览器端Cookie,必须改用客户端组件发起请求,或者在服务端手动透传浏览器携带的Cookie。
  • 不要修改Django会话Cookiesessionid的HTTP-only属性,仅需要保证csrftoken的HTTP-only为False即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 18:24:02