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

基于Clean Architecture开发RestApi应用时RepositoryImpl报错及优化咨询

问题解决与代码优化方案

一、报错原因与修复

1. 核心问题定位

报错The return type 'Future<User>' isn't a 'Future<HttpResponse<User>>', as required by the closure's context的本质是两个类型不匹配:

  • BaseApiRepository.getStateOf要求传入的request闭包必须返回Future<HttpResponse<T>>,但UserDataSource.getUserById返回的是Future<User>,缺少响应状态码等元数据。
  • IUserRepository定义的返回类型是Future<User>,但UserRepositoryImpl实际返回Future<DataState<User?>>,接口与实现的返回类型不一致。

2. 分步修复代码

(1)修改UserDataSource的返回类型

将Retrofit接口方法的返回类型改为Future<HttpResponse<User>>,保留响应完整信息:

import 'package:retrofit/http.dart';
import 'package:dio/dio.dart';
import 'package:retrofit/dio.dart'; // 需导入HttpResponse类

@RestApi(baseUrl: 'https://api.example.com/')
abstract class UserDataSource {
  factory UserDataSource(Dio dio) => UserDataSource(dio);

  @GET('/users/{id}')
  Future<HttpResponse<User>> getUserById(@Path() String id); // 修改返回类型
}

(2)对齐IUserRepository的返回类型

仓库接口需返回封装状态的DataState,而非直接返回实体类:

abstract class IUserRepository {   
  Future<DataState<User>> getUserById(String id); // 改为DataState<User>
}

(3)调整UserRepositoryImpl的实现

确保返回类型与接口一致,同时闭包返回类型匹配getStateOf的要求:

@Injectable(as: IUserRepository)
class UserRepositoryImpl extends BaseApiRepository implements IUserRepository {
  final UserDataSource _userDataSource;
  UserRepositoryImpl(this._userDataSource);

  @override
  Future<DataState<User>> getUserById(String id) {
    return getStateOf<User>(
      request: () => _userDataSource.getUserById(id),
    );
  }
}

二、DataState 优化方案

原DataState存在可空性不严谨、错误类型单一的问题,优化后增强类型安全性和扩展性:

import 'package:dio/dio.dart';

// 基础状态类,禁止直接实例化
abstract class DataState<T> {
  const DataState();
}

// 成功状态:强制携带非空数据
class DataSuccess<T> extends DataState<T> {
  final T data;
  const DataSuccess(this.data);
}

// 失败状态:支持任意错误类型,附带调用栈用于调试
class DataFailed<T> extends DataState<T> {
  final Object error;
  final StackTrace? stackTrace;
  const DataFailed(this.error, [this.stackTrace]);
}

优化点:

  • 移除原类中可空的data和error字段,确保成功状态必有数据,失败状态必有错误
  • 错误类型从固定DioException改为Object,支持处理非网络类错误
  • 添加StackTrace字段,方便调试时定位问题根源

三、BaseApiRepository 优化方案

原实现的状态码判断逻辑较局限,错误处理不够细化,优化后增强通用性和健壮性:

import 'dart:io' show HttpStatus;
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:retrofit/dio.dart';
import '../resources/data_state.dart';

abstract class BaseApiRepository {
  @protected
  Future<DataState<T>> getStateOf<T>({
    required Future<HttpResponse<T>> Function() request,
    // 可选:自定义成功状态码范围,提升灵活性
    List<int> successStatusCodes = const [HttpStatus.ok, HttpStatus.created],
  }) async {
    try {
      final httpResponse = await request();
      final response = httpResponse.response;

      if (successStatusCodes.contains(response.statusCode)) {
        // 校验数据非空,避免返回空数据的"成功"状态
        final data = httpResponse.data;
        if (data != null) {
          return DataSuccess(data);
        } else {
          throw const FormatException('接口返回数据为空');
        }
      } else {
        // 统一构建DioException处理非成功状态码
        throw DioException(
          requestOptions: response.requestOptions,
          response: response,
          type: DioExceptionType.badResponse,
        );
      }
    } on DioException catch (e, stackTrace) {
      // 网络请求类错误
      if (kDebugMode) {
        print('网络请求错误: ${e.message}');
      }
      return DataFailed(e, stackTrace);
    } on FormatException catch (e, stackTrace) {
      // 数据格式/解析错误
      if (kDebugMode) {
        print('数据格式错误: ${e.message}');
      }
      return DataFailed(e, stackTrace);
    } catch (e, stackTrace) {
      // 其他未知错误
      if (kDebugMode) {
        print('未知错误: $e');
      }
      return DataFailed(e, stackTrace);
    }
  }
}

优化点:

  • 允许自定义成功状态码范围,适配不同业务场景
  • 增加数据非空校验,避免无效的成功状态
  • 细化错误捕获分支,区分网络错误、格式错误和未知错误
  • 添加调试日志,方便开发阶段快速定位问题
  • 统一错误处理逻辑,减少重复代码

内容的提问来源于stack exchange,提问作者alshueili

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 06:36:06