为什么Axios无法设置CSRF Token请求头(Django+Next.js场景)
问题根因
- 当
csrftokenCookie被设置为HTTP-only、或者前后端跨域时,浏览器禁止JS读取该Cookie的值,Axios即使配置了xsrf相关参数也无法自动提取Cookie值填充到X-CSRFToken请求头。 - 未预先触发Django下发
csrftokenCookie的逻辑,Django默认仅在返回包含CSRF模板标签的页面、或者主动调用get_token方法时才会设置该Cookie。
方案1:同域部署场景(前后端域名/子域名一致)
- 先确认Django配置
CSRF_COOKIE_HTTPONLY = False,确保JS可以读取csrftoken Cookie - 手动读取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侧配置
- 新增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)})
- 配置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会话Cookie
sessionid的HTTP-only属性,仅需要保证csrftoken的HTTP-only为False即可。
内容的提问来源于stack exchange,提问作者awild
相关产品推荐
相关产品推荐

