
本文详解 Django 中因废弃 request.is_ajax() 导致的 400 Bad Request 问题,涵盖 CSRF 处理、JSON 解析、视图逻辑修正及前端注意事项,助你快速修复 AJAX 数据提交失败。
本文详解 django 中因废弃 `request.is_ajax()` 导致的 400 bad request 问题,涵盖 csrf 处理、json 解析、视图逻辑修正及前端注意事项,助你快速修复 ajax 数据提交失败。
在使用 Django 处理 JavaScript 发起的 AJAX POST 请求时,出现 400 Bad Request(如日志中 "POST /user_send_info/ HTTP/1.1" 400 98)是一个常见但易被忽略的问题。根本原因往往不在网络或路由,而在于Django 视图层的请求校验逻辑与现代前端实践不兼容。
? 核心问题:request.is_ajax() 已被弃用
Django 自 3.1 版本起正式移除 request.is_ajax() 方法(并在 4.0+ 中完全删除),该方法曾用于判断请求是否为 XMLHttpRequest。当前主流浏览器和 fetch API 发起的请求不会自动设置 HTTP_X_REQUESTED_WITH: 'XMLHttpRequest' 头,因此 request.is_ajax() 恒为 False,导致你的视图直接跳过 POST 分支,返回 status=400 的错误响应。
提供使用 django-unfold (v0.56+) 构建高级 Django 管理界面的专业指导。当用户提及 django-unfold、unfold admin 等内容时使用此技能。
✅ 正确做法是仅依赖 request.method == 'POST' 进行基础方法校验,并将业务逻辑(如 JSON 解析、数据校验)后置处理:
# views.py
import json
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
def email_view(request):
if request.method == 'POST':
try:
# ✅ 安全解析 JSON 请求体
data = json.loads(request.body.decode('utf-8'))
# ✅ 使用更健壮的键访问方式(避免 KeyError)
companyName = data.get('companyName')
userName = data.get('userName')
fullName = data.get('fullName')
email = data.get('email')
expireDate = data.get('dateFormatted')
version = data.get('version')
code = data.get('code')
# ✅ 可选:添加基础数据校验
if not all([companyName, email, code]):
return JsonResponse({'error': 'Missing required fields'}, status=400)
print("✅ Received:", {
'company': companyName,
'user': userName,
'email': email,
'expires': expireDate,
'code': code
})
return JsonResponse({
'success': True,
'message': 'Data received successfully.'
})
except json.JSONDecodeError:
return JsonResponse({'error': 'Invalid JSON in request body'}, status=400)
except Exception as e:
return JsonResponse({'error': f'Server error: {str(e)}'}, status=500)
# ❌ 不支持 GET 或其他方法
return JsonResponse({'error': 'Only POST requests allowed.'}, status=405)⚠️ 前端关键修正点
-
CSRF Token 传递必须正确
模板中 {{ csrf_token }} 在 JS 字符串中需确保已渲染(非字面量)。若在外部 .js 文件中使用,应通过 data-csrf 属性注入:<!-- 在 HTML 模板中 --> <body data-csrf="{{ csrf_token }}">// JS 中读取 const csrfToken = document.body.getAttribute('data-csrf'); // 替换 fetch headers 中的 '{{ csrf_token }}' headers: { 'Content-Type': 'application/json', 'X-CSRFToken': csrfToken, // ✅ 动态获取 } -
确保 URL 路由匹配且无拼写错误
确认 urls.py 中路径与 fetch() 目标一致(注意末尾斜杠):# urls.py path('user_send_info/', email_view, name='email_view'), # ✅ 推荐统一有/或无/ 添加错误处理与调试输出
在 fetch().catch() 中打印完整错误,并检查浏览器 Network 面板中的 Request Payload 和 Response Headers,确认 Content-Type: application/json 和 X-CSRFToken 已正确发送。
?️ 安全增强建议(可选)
- 若该接口无需 CSRF 保护(如公开 API),可添加 @csrf_exempt 装饰器(仅限明确场景):
from django.views.decorators.csrf import csrf_exempt @csrf_exempt def email_view(request): ...
- 更推荐方案:使用 @ensure_csrf_cookie 在页面加载时预设 cookie,并配合 getCookie() 函数动态读取 token。
✅ 总结
| 问题环节 | 错误表现 | 正确做法 |
|---|---|---|
| Django 视图 | request.is_ajax() 返回 False → 400 | 移除该条件,仅用 if request.method == 'POST' |
| JSON 解析 | json.loads(request.body) 报错 | 添加 decode('utf-8') 和异常捕获 |
| CSRF Token | 403 Forbidden 或静默失败 | 通过模板变量或 DOM 属性安全注入 |
| 前端调试 | 控制台无报错但后端无日志 | 检查 Network → Payload 是否为合法 JSON |
修复后,你的 AJAX 请求将稳定接收并返回 200 OK 响应,Django 后端也能准确打印所有字段值。记住:现代 Web 开发中,“是否为 AJAX” 已不再是服务端的职责,而是客户端明确声明内容类型与意图。

















