Django对接Axios发送POST请求出现CSRF token缺失403错误求助
问题根本原因
- 你配置的DRF权限规则仅对DRF视图生效,当前使用的
subscription是普通Django视图,默认强制开启CSRF校验,你的请求未携带合法CSRF凭证 - 此前添加请求头的操作完全错误:
Set-Cookie是服务端返回给客户端的响应头,客户端发请求时携带该字段不会生效,Django要求CSRF凭证放在**请求头X-CSRFToken**中,且需要和Cookie中携带的csrftoken值匹配 - 额外隐藏问题:当前Axios默认发送
application/json格式数据,普通Django视图的request.POST无法读取JSON数据,CSRF校验通过后也会报KeyError: 'email'错误
解决方案
方案1:适配普通Django视图(无需修改后端代码)
前端Axios代码修改
- 开启
withCredentials让请求自动携带Django种下的csrftokenCookie - 从Cookie中提取
csrftoken值,填入请求头X-CSRFToken字段 - 将请求数据格式改为表单格式,适配
request.POST读取逻辑
首先添加提取Cookie的工具函数:
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; }
修改后的请求代码:
const newsletterSignUp = async function (email) { try { // 构造表单格式数据 const formData = new FormData(); formData.append('email', email); let res = await axios({ method: "post", url: "http://127.0.0.1:8000/subscription", data: formData, withCredentials: true, headers: { "X-CSRFToken": getCookie('csrftoken') } }); return res; } catch (err) { console.error(err); return err; } }
如果是前后端分离跨域场景,需要额外修改Django配置:
- 安装
django-cors-headers依赖 - 修改
settings.py:
INSTALLED_APPS = [ # 原有app不变,新增下面一行 'corsheaders', ] MIDDLEWARE = [ # 放在中间件列表最顶部,新增下面一行 'corsheaders.middleware.CorsMiddleware', # 原有中间件保持不变 ] # 替换为你的前端实际访问地址,禁止使用* CORS_ALLOWED_ORIGINS = [ "http://前端地址:端口", ] CORS_ALLOW_CREDENTIALS = True # CSRF信任的跨域来源,和上面保持一致 CSRF_TRUSTED_ORIGINS = [ "http://前端地址:端口", ]
方案2:改造成DRF视图,适配JSON请求(更适合前后端分离场景)
修改views.py的subscription视图为DRF视图,自动适配JSON请求,CSRF校验规则和DRF权限对齐:
from rest_framework.decorators import api_view, permission_classes from rest_framework.permissions import AllowAny @api_view(['POST']) @permission_classes([AllowAny]) def subscription(request): if request.method == "POST": # 从DRF的request.data中读取数据,同时支持JSON/表单格式 email = request.data.get('email') if not email: return Response({"error": "邮箱不能为空"}, status=400) subscribe(email) return Response({"message": "Email received. thank You! "}, status=200) # GET请求保留原有渲染逻辑 return render(request, "index.html")
该方案下前端可以继续发送JSON格式请求,仅需要按方案1要求配置CSRF相关的头和withCredentials即可正常使用。
内容的提问来源于stack exchange,提问作者user16372363
相关产品推荐
相关产品推荐

