Django中如何检测请求payload缺失指定字段并通过异常处理?
原有代码的核心问题
- 异常捕获逻辑完全错误:如果
payload中不存在name字段,执行payload['name']时会直接抛出KeyError,根本不会触发你写的payload['name'].DoesNotExist;这个异常写法本身就是非法的,DoesNotExist是Django模型类专属的异常,字典不存在该异常类型 - 未处理JSON解析异常:如果请求Body不是合法JSON格式,
json.loads(request.body)会直接抛出JSONDecodeError - 响应格式不规范:指定了
content_type='text/json',但返回的是普通字符串,既不符合JSON格式规范,标准JSON响应的content-type应为application/json - 未处理非POST请求:如果收到GET、PUT等其他类型请求,接口会因无返回值报错
基础修复方案
直接修复原有逻辑的错误,覆盖所有异常场景:
import json from django.http import HttpResponse from django.views.decorators.csrf import csrf_exempt @csrf_exempt def my_method(request): if request.method != 'POST': return HttpResponse("\"INVALID_METHOD\"", content_type='application/json', status=405) try: payload = json.loads(request.body) name = payload['name'] return HttpResponse("\"YES\"", content_type='application/json') except json.JSONDecodeError: # 处理非合法JSON请求 return HttpResponse("\"INVALID_JSON\"", content_type='application/json', status=400) except KeyError: # 处理缺少name字段的场景 return HttpResponse("\"NO\"", content_type='application/json')
更优实现方案
方案1:用Django原生工具简化逻辑
使用JsonResponse和请求方法限制装饰器,减少重复代码:
import json from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_http_methods @csrf_exempt @require_http_methods(["POST"]) # 自动限制仅允许POST请求,非POST请求自动返回405 def my_method(request): try: payload = json.loads(request.body) except json.JSONDecodeError: return JsonResponse({"code": 400, "msg": "非法JSON格式"}, status=400) if "name" not in payload: return JsonResponse({"code": 200, "msg": "NO"}) # 此处可扩展name字段的合法性校验,比如是否为空、长度是否合规等 return JsonResponse({"code": 200, "msg": "YES"})
方案2:使用Django REST Framework(DRF)标准化校验
适合参数多、校验逻辑复杂的项目,自动处理JSON解析、参数校验逻辑:
from rest_framework import serializers from rest_framework.response import Response from rest_framework.decorators import api_view, authentication_classes, permission_classes # 定义参数校验规则 class RequestParamSerializer(serializers.Serializer): name = serializers.CharField(required=True, allow_blank=False) @api_view(['POST']) @authentication_classes([]) # 关闭默认身份校验,和原csrf_exempt效果对齐 @permission_classes([]) def my_method(request): ser = RequestParamSerializer(data=request.data) # 校验不通过时(缺少name、name为空等)直接返回NO if not ser.is_valid(): return Response({"msg": "NO"}) # 校验通过后可通过ser.validated_data['name']获取安全的参数值 return Response({"msg": "YES"})
内容的提问来源于stack exchange,提问作者reza_khalafi
相关产品推荐
相关产品推荐

