Flutter对接Django REST API时自定义错误提示异常排查
Flutter对接Django REST Framework注册错误处理解决方案
问题根源
后端返回500错误是因为用户名/密码的自定义校验未被DRF框架正确捕获,导致服务器抛出未处理异常;而邮箱校验由DRF内置序列化器处理,能正常返回400错误和提示信息。
后端修复步骤
1. 自定义校验在序列化器中正确抛出DRF的ValidationError
修改序列化器,将自定义校验逻辑放在validate_<字段名>方法中,抛出rest_framework.exceptions.ValidationError(而非Django core的ValidationError):
from rest_framework import serializers from rest_framework.exceptions import ValidationError from .custom_validation import validate_username, validate_password class UserRegisterSerializer(serializers.Serializer): username = serializers.CharField(max_length=150) email = serializers.EmailField() password = serializers.CharField(write_only=True, min_length=8) def validate_username(self, value): if not validate_username(value): raise ValidationError("用户名不符合规则(例:不能包含特殊字符,长度3-15位)") return value def validate_password(self, value): if not validate_password(value): raise ValidationError("密码不符合规则(例:至少包含1个大写字母、1个数字)") return value def create(self, validated_data): from django.contrib.auth.models import User user = User.objects.create_user( username=validated_data['username'], email=validated_data['email'], password=validated_data['password'] ) return user
2. 视图返回序列化器的错误信息
使用DRF的APIView,当序列化器验证失败时,返回400状态码和错误详情:
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from .serializers import UserRegisterSerializer class UserRegisterView(APIView): def post(self, request): serializer = UserRegisterSerializer(data=request.data) if serializer.is_valid(raise_exception=False): serializer.save() return Response({"msg": "注册成功"}, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
前端Flutter修复步骤
修改注册请求的错误处理逻辑,捕获400响应并解析后端返回的错误信息,避免FormatException:
import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:flutter/material.dart'; Future<void> handleRegister(BuildContext context, String username, String email, String password) async { final apiUrl = Uri.parse('http://你的后端地址/api/register/'); try { final response = await http.post( apiUrl, headers: {'Content-Type': 'application/json'}, body: jsonEncode({ 'username': username, 'email': email, 'password': password, }), ); if (response.statusCode == 201) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('注册成功!')), ); // 跳转登录页等后续逻辑 } else if (response.statusCode == 400) { final errorMap = jsonDecode(response.body) as Map<String, dynamic>; String errorMsg = ''; errorMap.forEach((key, value) { errorMsg += '${key.replaceAll('_', ' ')}: ${(value as List).join(' ')}\n'; }); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(errorMsg.trim())), ); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('服务器异常,请稍后重试')), ); } } on FormatException { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('服务器响应格式错误')), ); } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('注册失败:$e')), ); } }
关键注意点
- 后端必须用DRF的
ValidationError,不能用Django原生的,否则DRF无法捕获并返回标准400响应 - 前端要先判断响应状态码,再解析JSON,避免在500错误时强行解析导致FormatException
- 自定义校验函数的逻辑要明确,确保返回布尔值或直接抛出DRF的ValidationError
内容的提问来源于stack exchange,提问作者Mohamed Selmi
相关产品推荐
相关产品推荐

