Django登录接口POST请求持续返回400错误,求有效调试方案
问题诊断与解决方案
首先,你的400 Bad Request错误核心原因是请求格式不匹配:
你的SignInView中使用json.loads(request.body)来解析请求数据,但你用Httpie发送的默认请求是application/x-www-form-urlencoded格式(表单格式),而不是JSON格式。这会导致json.loads解析失败,触发异常,最终返回400错误。
快速修复方案
方案1:修改Httpie请求,发送JSON格式
用Httpie发送JSON请求,需要明确指定Content-Type,或者直接传递JSON字符串:
# 方式1:自动生成JSON http -v POST http://127.0.0.1:8000/account/signin username='aaron' password='1234' Content-Type:application/json # 方式2:直接传递JSON字符串 http -v POST http://127.0.0.1:8000/account/signin '{"username":"aaron","password":"1234"}'
方案2:修改Django视图,兼容表单数据
如果希望支持多种请求格式,可以在视图中同时处理JSON和表单数据:
class SignInView(View): def post(self, request): try: # 先尝试解析JSON data = json.loads(request.body) except json.JSONDecodeError: # 解析失败则尝试表单数据 data = request.POST.dict() try: # 后续登录逻辑不变 query = Q(email=data.get('email')) | Q(username=data.get('username')) | Q(fullname=data.get('fullname')) if Account.objects.filter(query).exists(): account = Account.objects.get(query) encoded_pw = account.password.encode('utf-8') encoded_input = data['password'].encode('utf-8') if bcrypt.checkpw(encoded_input, encoded_pw): token = jwt.encode({ 'email' : account.email }, 'secret', algorithm='HS256').decode('utf-8') return JsonResponse({ 'access_token' : token }, status=200) return HttpResponse(status=403) return HttpResponse(status=402) except KeyError: return JsonResponse({"message": "INVALID_KEYS"}, status=400) except Account.MultipleObjectsReturned: return JsonResponse({"message": "DUPLICATE_ACCOUNTS"}, status=400)
除了pdb和print的调试方法
Django Debug Toolbar
安装后,它会在页面底部显示请求详情,包括请求头、POST数据、异常栈、数据库查询等,能直观看到请求是否被正确解析。日志记录
在settings.py中配置日志,将请求和异常信息写入文件,方便事后排查:LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'debug_file': { 'level': 'DEBUG', 'class': 'logging.FileHandler', 'filename': './debug.log', }, }, 'loggers': { 'django.request': { 'handlers': ['debug_file'], 'level': 'DEBUG', 'propagate': True, }, }, }这样所有请求相关的异常和细节都会被记录到
debug.log中。返回原始请求信息
在视图开头临时添加代码,返回请求的原始内容和类型,快速定位格式问题:class SignInView(View): def post(self, request): # 临时调试:返回请求详情 return JsonResponse({ 'raw_body': request.body.decode('utf-8'), 'content_type': request.META.get('CONTENT_TYPE'), 'post_data': request.POST.dict() }) # 后续代码...使用Postman/Insomnia等可视化工具
这类工具可以直观地选择请求格式(JSON/表单),查看请求头和响应详情,比命令行更容易排查格式问题。捕获更细粒度的异常
除了KeyError,还要捕获JSONDecodeError和MultipleObjectsReturned等异常,返回更明确的错误信息:import json from django.core.exceptions import MultipleObjectsReturned class SignInView(View): def post(self, request): try: data = json.loads(request.body) except json.JSONDecodeError: return JsonResponse({"message": "INVALID_JSON_FORMAT"}, status=400) try: # 登录逻辑... except KeyError: return JsonResponse({"message": "INVALID_KEYS"}, status=400) except MultipleObjectsReturned: return JsonResponse({"message": "MULTIPLE_ACCOUNTS_MATCH"}, status=400)
额外优化建议
- 你的
Account.objects.get(...)可能会抛出MultipleObjectsReturned异常(比如多个用户有相同的fullname),必须捕获这个异常,避免服务器返回500错误。 - 考虑使用Django自带的
AbstractBaseUser和AuthenticationBackend来实现自定义认证,这样能更好地利用Django的认证系统,减少重复代码。
内容的提问来源于stack exchange,提问作者Nick
相关产品推荐
相关产品推荐

