Flutter中HTTP POST请求的201成功返回对象与422校验违规信息处理及页面展示问询
Flutter中HTTP POST请求的201成功返回对象与422校验违规信息处理及页面展示问询
嘿,我完全懂你的需求——现在你不想只靠布尔值判断请求结果,而是希望成功时拿到完整的Apartment对象,遇到422校验错误时能精准获取违规信息并展示在表单对应字段上。下面我一步步帮你实现这个功能:
1. 定义统一的请求结果类型
首先我们需要一个能明确区分「成功/失败」状态的类型,这样Repository可以清晰返回不同场景的结果。我们可以用Dart的密封类来实现:
sealed class ApiResult<T> {} class Success<T> extends ApiResult<T> { final T data; Success(this.data); } class Failure<T> extends ApiResult<T> { final HttpViolations errors; Failure(this.errors); }
这个类能帮我们把「携带创建好的Apartment对象的成功响应」和「携带校验违规信息的失败响应」区分开,后续处理时更清晰。
2. 修改ApartmentRepository的createApartment方法
把原来返回Future<bool>改成返回Future<ApiResult<Apartment>>,然后针对性处理不同状态码的响应:
Future<ApiResult<Apartment>> createApartment(Apartment apartment) async { String path = baseUrl; initAdapter(_dio); _dio.options.headers['accept'] = 'application/json'; _dio.options.headers['Content-Type'] = 'application/json'; try { var response = await _dio.post(path, data: apartment.toJson()); if (response.statusCode == 201) { // 将接口返回的JSON转成Apartment对象(需要确保Apartment有fromJson工厂方法) final createdApartment = Apartment.fromJson(response.data); return Success(createdApartment); } else if (response.statusCode == 422) { // 解析422响应里的违规信息 final violations = HttpViolations.fromJson(response.data); return Failure(violations); } else { // 其他状态码可根据业务需求处理,比如抛出异常或返回默认失败 throw Exception('Unexpected status code: ${response.statusCode}'); } } on DioException catch (e) { // 捕获Dio请求异常,若为422则同样解析违规信息 if (e.response?.statusCode == 422) { final violations = HttpViolations.fromJson(e.response!.data); return Failure(violations); } rethrow; // 其他异常可重新抛出或自定义处理 } }
提示:你需要给Apartment类补充fromJson工厂构造方法,才能把接口返回的JSON转成实体对象。
3. 在ApartmentForm中处理请求结果并展示错误
首先在表单类里添加一个存储字段错误的变量:
Map<String, String> _fieldErrors = {};
然后修改按钮点击逻辑,处理ApiResult的不同状态:
child: StyledElevatedSaveFormButton( onPressed: () async { if (_apartmentFormKey.currentState?.validate() ?? false) { _apartmentFormKey.currentState?.save(); // 清空之前的错误信息 setState(() { _fieldErrors.clear(); }); Apartment newApartment = Apartment( ref: refController.text, apartmentType: _selectedApartmentType.type, area: int.parse(areaController.text), address: addressController.text, zipCode: zipCodeController.text, city: cityController.text, ); ApiResult<Apartment> result; if (widget.apartment?.id == null) { result = await ApartmentRepository().createApartment(newApartment); } else { // 注意:updateApartment方法也需要同步改成返回ApiResult类型哦 Apartment newApartmentUpdate = newApartment.copyWith(iriId: widget.apartment!.iriId); result = await ApartmentRepository().updateApartment(newApartmentUpdate); } if (result is Success) { // 请求成功:执行跳转并显示成功提示 onButtonPressed(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('公寓创建/更新成功!')), ); } else if (result is Failure) { // 请求失败:解析违规信息,更新字段错误映射 setState(() { for (var violation in result.errors.violations) { _fieldErrors[violation.propertyPath] = violation.message; } }); } } }, isLoding: isLoading, ),
4. 在表单字段上绑定错误信息
最后,把每个TextFormField的errorText绑定到_fieldErrors对应的key上,比如:
TextFormField( controller: refController, decoration: InputDecoration( labelText: '参考编号', errorText: _fieldErrors['ref'], // 绑定ref字段的错误提示 ), // 其他验证逻辑... ), TextFormField( controller: addressController, decoration: InputDecoration( labelText: '地址', errorText: _fieldErrors['address'], // 绑定address字段的错误提示 ), // 其他验证逻辑... ),
这样当接口返回422错误时,对应的表单字段就会自动显示对应的违规提示了。
补充提示
- 务必给
Apartment类实现fromJson工厂方法,否则无法解析接口返回的成功响应; - 如果
updateApartment也需要相同的错误处理逻辑,记得同步修改它的返回类型和实现; - 对于网络异常、500等非422错误,可以在catch块里添加通用错误提示,比如用SnackBar显示「请求失败,请稍后重试」。
内容来源于stack exchange
相关产品推荐
相关产品推荐

