Django类视图POST请求报CSRF token missing 403错误
报错原因
返回403是Django内置的CSRF跨站请求伪造防护机制触发导致的。
Django默认会对所有非安全请求(POST/PUT/DELETE等,GET/HEAD/OPTIONS等请求不会触发)做CSRF令牌校验,请求未携带有效CSRF令牌时会直接拦截返回403,和你日志里的CSRF token missing报错完全对应。你的GET请求可以正常运行,就是因为GET属于默认放行的安全请求,不会触发该校验。
另外你的POST方法代码还有两个隐藏问题:
- 测试时你把
name参数放在URL查询串(?name=xxx)里,但代码里从request.POST取值,这个对象只能获取请求体中表单格式提交的参数,URL上的查询参数需要从request.GET获取,会导致拿不到name值 return HttpResponse(201)写法错误,直接传201会被当成响应内容,状态码默认返回200,需要显式指定status=201
修复方案
根据你的接口使用场景二选一即可:
场景1:接口供站内网页表单/AJAX调用
不需要关闭CSRF防护,按规范携带CSRF令牌即可:
- 原生Django模板渲染的表单,在表单标签内加入
{% csrf_token %}模板标签,提交时会自动携带有效令牌 - AJAX请求场景,先从cookie中读取
csrftoken字段值,将其放到请求头X-CSRFToken中随请求发送即可通过校验
场景2:接口是纯API,供第三方/客户端调用
直接给类视图添加CSRF豁免装饰器,跳过该校验即可,修改后的完整代码如下:
首先导入需要的依赖:
from django.http import HttpResponse, HttpResponseForbidden, JsonResponse from django.views import View from django.views.decorators.csrf import csrf_exempt from django.utils.decorators import method_decorator # 原有业务依赖保留 # from xxx import check_correct_api_secret, paginate, serialize_category_list, Category
修改类视图添加装饰器,同时修正POST方法的参数取值和响应写法:
@method_decorator(csrf_exempt, name='dispatch') class CategoryListView(View): def get(self, request): if not check_correct_api_secret(request): return HttpResponseForbidden('Unknown API key') query_set = Category.objects.all() query_params = request.GET query_set = paginate(query_params, query_set) items_data = serialize_category_list(request, query_set) return JsonResponse(items_data, safe=False) def post(self, request): # 如果是URL查询串传name参数用request.GET取值 # 如果是请求体表单传参,换回request.POST.get('name') name = request.GET.get('name') Category.objects.create(name=name) return HttpResponse(status=201)
路由配置不需要修改,改完之后重启服务POST请求即可正常访问。
内容的提问来源于stack exchange,提问作者Sergey
相关产品推荐
相关产品推荐

