Axios请求未向Django服务器发送预期Cookie头问题排查
React 上传文件到 Django 时 CSRF 验证失败的问题解决
问题背景
在 React 应用中使用 Axios 发送 POST 请求向 Django 服务器上传文件,服务器要求请求包含 CSRF Cookie,但尝试了多种设置方式(document.cookie 手动设置、开启 withCredentials: true、指定 Cookie 请求头)均无效。添加 @csrf_exempt 装饰器后请求正常,确认问题出在 CSRF 验证环节。
相关代码片段
Axios 请求代码
const onSubmit = async (data) => { const formData = new FormData() formData.append('file', data.file[0]) const csrftoken = getCookie('csrftoken'); document.cookie = `csrftoken=${csrftoken}` const res = await axiosInstance.post('/upload/', formData, { timeout: 0, headers: { 'Cookie': `csrftoken=${csrftoken}`, 'Content-Type': 'multipart/form-data', 'x-csrftoken': csrftoken, }, withCredentials: true, }) console.log(res) }
Django 视图代码
def upload_file(request): form = UploadFileForm() if request.method == 'POST': form = UploadFileForm(request.POST, request.FILES) if form.is_valid(): file_id = save_file_to_database(request.FILES['file']) response = JsonResponse({'id': file_id}, status=201) return response else: response = HttpResponse({'message': 'Upload failed'}, status=400) return response return render(request, 'upload.html', {'form': form})
Django settings.py 配置
CORS_ORIGIN_WHITELIST = ( "http://localhost:8000", "http://127.0.0.1:5173", ) CSRF_TRUSTED_ORIGINS = [ "http://127.0.0.1:5173" ] SESSION_COOKIE_SAMESITE = 'None'
解决方法
1. 修正 CSRF Token 传递逻辑
Django 的 CSRF 验证优先读取 X-CSRFToken 请求头,手动设置 Cookie 头会被浏览器同源策略拦截(浏览器会自动管理 Cookie,手动注入的 Cookie 不被认可)。同时需注意:
- 移除手动设置
document.cookie的代码,确保csrftokenCookie 是从 Django 服务器正常获取的(提前通过 GET 请求访问 Django 页面或接口) - 只保留
X-CSRFToken请求头,统一为标准大写开头写法 - 不要手动设置
Content-Type: multipart/form-data,Axios 会自动根据 FormData 生成带边界值的正确头
修改后的 Axios 代码:
const onSubmit = async (data) => { const formData = new FormData() formData.append('file', data.file[0]) const csrftoken = getCookie('csrftoken'); const res = await axiosInstance.post('/upload/', formData, { timeout: 0, headers: { 'X-CSRFToken': csrftoken, }, withCredentials: true, }) console.log(res) }
2. 完善 Django 跨域及 Cookie 配置
当前配置缺少关键的跨域凭证允许和 CSRF Cookie 单独设置,补充如下:
CORS_ORIGIN_WHITELIST = ( "http://localhost:8000", "http://127.0.0.1:5173", ) CORS_ALLOW_CREDENTIALS = True # 允许跨域请求携带凭证(关键) CSRF_TRUSTED_ORIGINS = [ "http://127.0.0.1:5173" ] SESSION_COOKIE_SAMESITE = 'None' SESSION_COOKIE_SECURE = True # 本地 HTTP 开发可临时设为 False,生产环境必须开启 CSRF_COOKIE_SAMESITE = 'None' # 单独配置 CSRF Cookie 的 SameSite 属性 CSRF_COOKIE_SECURE = True # 本地 HTTP 开发可临时设为 False
3. 确保 getCookie 函数正确性
使用标准的 Cookie 提取逻辑,避免因函数错误导致无法获取 csrftoken:
function getCookie(name) { let cookieValue = null; if (document.cookie && document.cookie !== '') { const cookies = document.cookie.split(';'); for (let i = 0; i < cookies.length; i++) { const cookie = cookies[i].trim(); if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; }
4. 验证请求头
打开浏览器开发者工具的 Network 标签,检查 POST 请求的 Request Headers:
- 确认
Cookie头包含csrftoken=xxx - 确认
X-CSRFToken头值与 Cookie 中的csrftoken一致
若 Cookie 未携带,检查:
- React 应用域名是否在
CORS_ORIGIN_WHITELIST和CSRF_TRUSTED_ORIGINS中 withCredentials: true是否正确设置- 浏览器是否允许第三方 Cookie(本地开发建议用
127.0.0.1而非localhost,避免跨域 Cookie 限制)
内容的提问来源于stack exchange,提问作者Felipe Martins
相关产品推荐
相关产品推荐

