You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中AJAX请求CSRF Token缺失问题排查与解决

问题解决与优化方案

核心错误修复

你遇到的CSRF token missing报错,根源就是PUT请求代码里把fetch配置的headers写成了大写的Headers——fetch API的配置对象中,请求头的属性名是小写的headers,大写属性会被忽略,导致CSRF Token根本没被携带到请求里,所以Django判定Token缺失。

修正后的PUT请求代码:

fetch(`/edit/login=${id}`, { // 修正原URL多余的右大括号
    method: "PUT",
    headers: { // 改成小写headers
        "X-CSRFToken": getCookie("csrftoken"),
        "Content-Type": "application/json",
    },
    mode: "same-origin",
    body: JSON.stringify(body),
})

关于Token不同却报缺失的疑问

每个表单的CSRF Token不同是正常的——Django会为每个请求(或会话周期)生成独立的Token,这是防止CSRF攻击的安全设计。你之前的报错是Token缺失而非无效,正是因为大小写错误导致请求根本没带上Token,Django连验证的机会都没有,自然报缺失。

更简便的实现方式

1. 直接复用表单里的CSRF Token

既然你通过GET请求获取了Django渲染的表单,表单里已经包含{% csrf_token %}生成的隐藏字段,直接从表单里提取更省事,不用写getCookie函数:

// 假设edit_form是你创建的表单元素
const csrfToken = edit_form.querySelector('[name="csrfmiddlewaretoken"]').value;

fetch(`/edit/login=${id}`, {
    method: "PUT",
    headers: {
        "X-CSRFToken": csrfToken,
        "Content-Type": "application/json",
    },
    mode: "same-origin",
    body: JSON.stringify(body),
})

2. 封装通用的带CSRF的fetch函数

避免每次写请求都重复处理CSRF,封装一个工具函数:

function csrfFetch(url, options = {}) {
    const csrfToken = document.querySelector('[name="csrfmiddlewaretoken"]')?.value || getCookie("csrftoken");
    options.headers = {
        ...options.headers,
        "X-CSRFToken": csrfToken,
        "Content-Type": "application/json",
    };
    options.mode = "same-origin";
    return fetch(url, options);
}

// 使用示例
csrfFetch(`/edit/login=${id}`, {
    method: "PUT",
    body: JSON.stringify(body),
})

3. 用POST模拟PUT请求(Django原生支持)

Django支持通过POST请求携带_method=PUT参数来模拟PUT请求,这样可以直接利用表单的提交逻辑,不用手动处理AJAX的headers:

// 提交表单时改成POST,携带_method参数
const formData = new FormData(edit_form);
formData.append("_method", "PUT");

fetch(`/edit/login=${id}`, {
    method: "POST",
    body: formData,
    mode: "same-origin",
})

这种方式下,Django会把请求识别为PUT,同时自动处理CSRF验证(因为表单里已经有CSRF Token字段)。

Views.py的补充修正

你的views.py还有几个小问题需要修复:

from django.http import JsonResponse, Http404
from django.views.decorators.http import require_http_methods
from django.contrib.auth.decorators import login_required

# 用装饰器限制请求方法,更清晰
@login_required
@require_http_methods(["GET", "PUT"])
def edit_login(request, id):
    try:
        login = Entry.objects.get(id=id, owner=request.user) # 提前过滤用户权限,避免后续判断
    except Entry.DoesNotExist:
        raise Http404("Entry not found")

    if request.method == "GET":
        initial = {
            "title": login.title,
            "username": login.username,
            "password": login.password,
            "note": login.note,
            "folder": login.folder,
            "protected": login.protected,
            "favorite": login.favorite,
        }
        form = LoginForm(initial=initial) # 修复原代码变量名错误
        return render(request, 'vault/new_item.html', {"entry_form": form, 'uri_field': uri})
     
    elif request.method == "PUT":
        data = json.loads(request.body)
        # 这里添加实际的更新逻辑,比如:
        # login.title = data.get("title", login.title)
        # login.save()
        print("test")
        return JsonResponse({"message": "Successfully edited"}, status=200 )
  • 用@require_http_methods限制请求方法,更规范
  • 提前通过Entry.objects.get(id=id, owner=request.user)过滤用户权限,避免获取不属于当前用户的条目
  • 修复了initial=edit的变量名错误,改成initial=initial
  • 添加了try-except处理条目不存在的情况,返回404

内容的提问来源于stack exchange,提问作者Divroth

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 21:10:29