django 接受 POST 数据时提示 403 错误

同一个地址用 GET 方式可以正常访问,但在 POST 提交数据时返回 403 错误,通常是 Django 的 CSRF 校验没有通过。

Django 默认启用 CSRF 防护。只要项目中配置了:

'django.middleware.csrf.CsrfViewMiddleware',

POST 请求就需要带上合法的 CSRF token。否则 Django 会拒绝请求并返回 403。

推荐方法:提交 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。

Leave a Reply