【Flutter 必备插件】HTTP 封装 dio

什么是 dio

dio 是一个强大的 HTTP 网络请求库,支持全局配置、Restful API、FormData、拦截器、 请求取消、Cookie 管理、文件上传/下载、超时、自定义适配器、转换器等。

实战:HTTP 网络请求封装

dart 复制代码
dart
 体验AI代码助手
 代码解读
复制代码
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());
    }
  }
}

使用示例

javascript 复制代码
javascript
 体验AI代码助手
 代码解读
复制代码
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. 证书验证问题
ini 复制代码
ini
 体验AI代码助手
 代码解读
复制代码
// 忽略证书验证
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. 请求取消后的内存泄露
scss 复制代码
scss
 体验AI代码助手
 代码解读
复制代码
// 在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();
}
相关推荐
风清云淡_A5 小时前
【Flutter3.8x】flutter从入门到实战基础教程(四):自定义实现一个自增的StatefulWidget组件
前端·flutter
叽哥11 小时前
dart学习第1节: 变量与数据类型 —— 程序的 “基本元素”
flutter
喝拿铁写前端1 天前
Flutter 学习笔记 - 搭建(macOS 版)
前端·flutter
ALLIN1 天前
Mac Flutter fvm 多版本管理安装与常用指令(详细使用)
flutter
梦想改变生活1 天前
《Flutter篇第二章》MasonryGridView瀑布流列表
android·flutter
SoaringHeart2 天前
Flutter小技巧:IM音浪效果实现
前端·flutter
Bryce李小白3 天前
Flutter中实现页面跳转功能
flutter
RaidenLiu3 天前
Flutter 多环境配置:flavor
前端·flutter
忆江南3 天前
Widget 、 Element 和 RenderObject 关系
flutter