You need to enable JavaScript to run this app. 使用原生JS向Django发送AJAX POST请求配置CSRF头仍报403错误求解决
优惠活动
大模型
产品
解决方案
定价
更多

使用原生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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.31 04:45:07