同一个地址用 GET 方式可以正常访问,但在 POST 提交数据时返回 403 错误,通常是 Django 的 CSRF 校验没有通过。
Django 默认启用 CSRF 防护。只要项目中配置了:
'django.middleware.csrf.CsrfViewMiddleware',
POST 请求就需要带上合法的 CSRF token。否则 Django 会拒绝请求并返回 403。
Table of Contents
推荐方法:提交 CSRF token
如果是普通表单,在模板里的 <form> 标签内部加入:
<form method="post">
{% csrf_token %}
<!-- form fields -->
<button type="submit">Submit</button>
</form>
这样 Django 会在页面中生成隐藏字段,POST 时一起提交,CSRF 校验就能通过。
如果是 Ajax 请求,需要把 CSRF token 放到请求头里。常见做法是从 cookie 中读取 csrftoken,然后随 POST 请求发送:
fetch('/your-url/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrftoken
},
body: JSON.stringify({ name: 'value' })
})
方法 1:关闭 CSRF 中间件
可以在 settings.py 中注释掉这一行:
'django.middleware.csrf.CsrfViewMiddleware',
这样 POST 请求就不会再因为 CSRF 校验失败而返回 403。
不过这会关闭整个项目的 CSRF 防护,不建议在正式环境中使用。除非是在本地测试或非常明确的内部接口场景,否则应优先使用 CSRF token。
方法 2:对单个视图关闭 CSRF 校验
如果只是某个接口不需要 CSRF 校验,可以在 view 的 request handler 前面加上 @csrf_exempt:
# views.py
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def index(request):
return HttpResponse('ok')
这种方式只影响被装饰的视图,比关闭整个中间件范围更小。但它仍然会让该接口跳过 CSRF 防护,所以只应在确实需要时使用,例如第三方回调接口、内部服务接口,或者已经有其他认证和签名机制的 API。
