React表单POST请求Django后端遇CSRF cookie未设置禁止错误排查
问题原因及解决方案
1. 异步函数调用错误
getCSRFToken是异步函数,直接赋值let csrftoken = getCSRFToken()得到的是Promise对象,而非实际的token值,导致请求头里的X-CSRFToken无效。
修复代码:
在createListing中用await获取真实token,同时给fetch请求添加credentials: 'include'确保跨域场景下携带cookie:
async function getCSRFToken() { const response = await fetch("http://127.0.0.1:8000/getCSRFToken", { credentials: 'include' // 确保保存Django设置的CSRF cookie }); const jsonResponse = await response.json(); console.log("CSRFToken: ", jsonResponse["token"]); return jsonResponse["token"]; } async function createListing(listing) { let csrftoken = await getCSRFToken(); // 用await获取实际token值 const response = await fetch( "http://127.0.0.1:8000/createListing/", { method: "POST", body: JSON.stringify(listing), headers: { "Content-Type": "application/json", "X-CSRFToken": csrftoken }, credentials: 'include' // 跨域请求携带凭证,必填 } ); const data = await response.json(); return data; }
2. Django跨域配置缺失
跨域场景下,需配置Django允许前端域名的请求,并允许携带凭证:
安装并配置CORS插件
- 安装依赖:
pip install django-cors-headers
- 修改
settings.py:
INSTALLED_APPS = [ # ... 其他已安装应用 'corsheaders', ] MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', # 必须放在CommonMiddleware之前 'django.middleware.common.CommonMiddleware', # ... 其他中间件 ] # 允许的前端域名 CORS_ALLOWED_ORIGINS = [ "http://localhost:3001", ] # 允许跨域请求携带凭证(关键,否则cookie无法传递) CORS_ALLOW_CREDENTIALS = True # 配置CSRF信任的前端域名 CSRF_TRUSTED_ORIGINS = [ "http://localhost:3001", ]
3. 验证CSRF Cookie有效性
Django的CSRF验证需要同时满足两个条件:
- 请求头
X-CSRFToken的值与CSRF cookie一致 - 请求携带了CSRF cookie
可以通过浏览器开发者工具的Application -> Cookies查看127.0.0.1:8000下是否存在csrftoken cookie,若不存在,检查getCSRFToken请求是否添加了credentials: 'include',以及Django的CORS配置是否正确。
4. 可选:简化CSRF Token获取方式
无需单独写getCSRFToken接口,直接从cookie中读取token,减少额外请求:
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; } async function createListing(listing) { let csrftoken = getCookie('csrftoken'); const response = await fetch( "http://127.0.0.1:8000/createListing/", { method: "POST", body: JSON.stringify(listing), headers: { "Content-Type": "application/json", "X-CSRFToken": csrftoken }, credentials: 'include' } ); const data = await response.json(); return data; }
这种方式需要前端在初始化时(比如页面加载)发送一个带credentials: 'include'的GET请求到Django,触发CSRF cookie的设置。
内容的提问来源于stack exchange,提问作者waffledood
相关产品推荐
相关产品推荐

