使用原生JS向Django发送AJAX POST请求配置CSRF头仍报403错误求解决
原生JS发Django AJAX 触发403 问题修复
触发403的具体代码问题
你遇到的403完全是CSRF防护校验未通过导致的,逐行检查你的代码,一共4处明确的问题会直接触发校验拦截:
var data = '{% csrf_token %}'取到的根本不是有效CSRF token。这个标签在模板里渲染完成后是一段完整的<input>标签HTML字符串,不是纯token值,打印出来就能看到内容,把整段HTML当token塞到请求头里,Django不可能校验通过。- 请求头名称写错。Django默认识别的CSRF请求头是
X-CSRFToken(没有中间的横杠),你写的X-CSRF-Token不符合默认配置,就算token值对了,Django也读不到对应的校验值。 - 请求参数传递方式错误。
xhr.send()方法不支持直接传入普通JS对象,传进去会被自动序列化成[object Object]字符串,服务端根本收不到结构化的POST参数。 - 取值逻辑的适配性问题。如果JS代码是独立的静态文件、没有经过Django模板渲染,模板标签
{% csrf_token %}会直接以原字符串的形式输出,完全拿不到真实的CSRF值。
可直接运行的修复代码
// 从cookie中读取CSRF token,适配所有JS运行场景(包括独立静态文件) 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 csrftoken = getCookie('csrftoken'); const xhr = new XMLHttpRequest(); // 替换为你实际的后端接口路径,不要留空字符串 xhr.open('POST', '/api/your-target-path/'); // 配置正确的请求头 xhr.setRequestHeader('X-CSRFToken', csrftoken); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.onload = function(){ console.log(xhr.readyState); console.log(xhr.status); if(xhr.status === 200){ console.log(JSON.parse(xhr.responseText)); }else{ console.log("Something went wrong!!"); } } // 把JS对象序列化为JSON字符串再发送,和Content-Type头匹配 xhr.send(JSON.stringify({'userId' : userId}))
其他可选项调整
- 如果是在HTML内联脚本里写JS,不需要写取cookie的逻辑,可以直接从页面渲染的CSRF input标签取值:
const csrftoken = document.querySelector('input[name="csrfmiddlewaretoken"]').value,效果完全一致。 - 如果不想发JSON格式的请求,可以把参数部分替换为表单格式,同时调整Content-Type:
// 表单格式传参 const formData = new URLSearchParams({'userId': userId}); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send(formData.toString()) - 如果你的Django项目自定义了
CSRF_HEADER_NAME配置,要对应调整请求头名称,和配置保持一致即可。
内容的提问来源于stack exchange,提问作者sashi dhar
相关产品推荐
相关产品推荐

