You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 08:54:53