【Flutter 必备插件】HTTP 封装 dio

2026-04-15
【Flutter 必备插件】HTTP 封装 dio 关注 作者 关注 作者 关注 作者 关注 作者 2025/07/16 11:25

什么是 dio

dio 是一个强大的 HTTP 网络请求库,支持全局配置、Restful API、FormData、拦截器、 请求取消、Cookie 管理、文件上传/下载、超时、自定义适配器、转换器等。 小宝影院xiaobaotv.video iyftvyfsp.app a5game a5game.app slot a5game.app 爱壹帆电影yfsp.app xiaobao xiaobaotv.video 华人影视xiaobaotv.video 爱壹帆电影 yfsp.app 小宝影院电影xiaobaotv.video demotigrinho a5game.app plataformademo a5game.app fortunetigerbônusgrátissemdepósito a5game.app slotdemo a5game.app 电影爱壹帆yfsp.app plataformademográtis a5game.app 爱壹帆影视yfsp.app 寻秦记爱壹帆yfsp.app 爱一番yfsp.app sweetbonanza1000demo a5game.app 免费在线影院xiaobaotv.video fortuneoxdemográtis a5game.app ifvodyfsp.app fortunetigerdemográtis a5game.app pragmaticplay a5game.app 一帆yfsp.app ifun yfsp.app iyf yfsp.app slots a5game.app pragmatic a5game.app 海外华人视频网xiaobaotv.video pglucky88 a5game.app sugarrush1000demo a5game.app 小宝影院在线视频xiaobaotv.video Caça-níqueis a5game.app 爱壹帆寻秦记yfsp.app 爱壹帆免费版yfsp.app Cassinos a5game.app ifuntvyfsp.app nba比分 a5game.app 小寶影院电影xiaobaotv.video 爱亦凡yfsp.app 爱壹帆yfsp.app slotpix a5game.app demo a5game.app JogodoTigrinho a5game.app 一帆视频yfsp.app jogosdemopg a5game.app tigrinho gratis a5game.app 爱壹帆国际版 yfsp.app jogodotigrinhodemo a5game.app 爱壹帆在线yfsp.app pgslot a5game.app pgdemo a5game.app pgslotgacor a5game.app 小寶影院xiaobaotv.video 足球比分 a5game.app 电影小宝影院xiaobaotv.video aiyifan yfsp.app pg a5game.app iyifanyfsp.app fortunedragon demo a5game.app slotsdemo a5game.app tigrinhodemo a5game.app 爱一帆 yfsp.app demo a5game.app fortunetigerdemográtis a5game.app plataformademográtis a5game.app iyf yfsp.app nba比分 a5game.app

实战:HTTP 网络请求封装

class HttpUtil {

  late Dio _dio;
  // 单例模式
  static final HttpUtil _instance = HttpUtil._internal();

  factory HttpUtil() => _instance;

  HttpUtil._internal() {

    _dio = Dio(
        BaseOptions(
            baseUrl: AppConst.baseUrl,
            headers: {
              'platformId': AppConst.platformId,
              'tenant-id': 1,
            }
        )
    );

    _dio.interceptors.add(LogInterceptor(responseBody: true));

    _dio.interceptors.add(InterceptorsWrapper(
      onRequest: (RequestOptions options, RequestInterceptorHandler handler) async {

        if (options.headers['Authorization'] == null && UserStorage.getAccessToken() != null) {
          options.headers['Authorization'] = 'Bearer ${UserStorage.getAccessToken()}';
        }

        return handler.next(options);
      },
      onResponse: (Response<dynamic> response, ResponseInterceptorHandler handler) async {

        if (response.data['code'] == 0 || response.data['code'] == "00000") {

        } else if (response.data['code'] == 401) {
            if (UserStorage.getRefreshToke() != null && !response.requestOptions.path.contains('/auth/refresh')) {

              ApiResponse<Token> newToken = await _refreshToken(UserStorage.getRefreshToke()!);
              UserStorage.setToken(newToken.data!);

              response.requestOptions.headers['Authorization'] = 'Bearer ${newToken.data?.accessToken}';

              _dio.options.headers['Authorization'] = 'Bearer ${newToken.data?.accessToken}';

              final reResponse = await _dio.fetch(response.requestOptions);
              return handler.resolve(reResponse);
            } else {

              _dio.options.headers['Authorization'] = null;

              UserStorage.clearAll();
            }
        } else {
          // todo toast 展示
        }

        return handler.next(response);
      },
      onError: (DioException error, ErrorInterceptorHandler handler) async {

        return handler.next(error);
      },
    ));
  }

  Future<T> get<T> ( String path, { Map<String, dynamic>? params, Options? options, CancelToken? cancelToken} ) async {
    try {
      final response = await _dio.get(
        path,
        queryParameters: params,
        options: options,
        cancelToken: cancelToken,
      );
      return response.data;
    } catch (e) {
      throw ApiException(e.toString());
    }
  }

  Future<T> post <T> ( String path, { dynamic data, Map<String, dynamic>? params, Options? options, CancelToken? cancelToken,}) async {
    try {
      final response = await _dio.post(
        path, data:
        data,
        queryParameters: params,
        options: options,
        cancelToken: cancelToken,
      );
      return response.data;
    } catch (e) {
      throw ApiException(e.toString());
    }
  }
}

使用示例

static Future<ApiResponse<Token>> _refreshToken(String refreshToken) async {
    final response = await HttpUtil().post('/system/auth/refresh-token',
        params: { 'refreshToken': refreshToken} );
    return ApiResponse<Token>.fromJson(response, (json) => Token.fromJson(json));

性能优化建议

  1. 合理使用拦截器
    • 避免在拦截器中进行耗时操作
    • 使用异步操作时注意处理异常
  2. 请求优化
    • 合理设置超时时间
    • 使用cancelToken取消不必要的请求
    • 避免频繁的重复请求
  3. 缓存策略
    • 针对不常变化的数据实现缓存
    • 设置合理的缓存过期时间
    • 考虑使用本地存储持久化缓存
  4. 错误处理
    • 实现统一的错误处理机制
    • 合理使用重试机制
    • 提供友好的错误提示

FAQ【干货】

  1. 证书验证问题
// 忽略证书验证
dio.options.validateStatus = (status) {
  return status! < 500;
};

// 或者自定义证书验证
(dio.httpClientAdapter as IOHttpClientAdapter).onHttpClientCreate = 
  (HttpClient client) {
    client.badCertificateCallback =
        (X509Certificate cert, String host, int port) => true;
    return client;
  };
  1. 请求取消后的内存泄露
// 在dispose时取消所有请求
final _cancelTokens = <CancelToken>[];

void addCancelToken(CancelToken token) {
  _cancelTokens.add(token);
}

@override
void dispose() {
  for (final token in _cancelTokens) {
    token.cancel();
  }
  _cancelTokens.clear();
  super.dispose();
}
00目录 0
    讨论 我来说一句 发布发表评论 发布0等 0 人为本文章充电 还没有介绍自己 关注