dio property

Dio get dio

获取 Dio 实例(公开访问,方便特殊处理) 注意:使用前必须先调用 configure() 进行配置

注意:由于 Dart 的单线程模型,这里不会有真正的竞态条件 但为了代码清晰,我们使用双重检查模式

Implementation

static dio_package.Dio get dio {
  // 双重检查,确保线程安全(虽然 Dart 单线程,但为了代码清晰)
  if (_dioInstance == null) {
    if (_config == null) {
      throw StateError('HttpUtil 未配置,请先调用 HttpUtil.configure() 进行配置');
    }

    // 再次检查,防止在检查后、赋值前配置被修改(虽然不太可能)
    if (_dioInstance == null) {
      _dioInstance = dio_package.Dio();
      _dioInstance!.options = dio_package.BaseOptions(
        baseUrl: _config!.baseUrl,
        connectTimeout: const Duration(seconds: 30),
        receiveTimeout: const Duration(seconds: 30),
        sendTimeout: const Duration(seconds: 30),
        // 所有状态码都认为是有效的,不自动抛出异常
        validateStatus: (status) => true,
      );

      // 先添加请求拦截器,自动添加请求头(必须在日志拦截器之前)
      _dioInstance!.interceptors.add(
        dio_package.InterceptorsWrapper(
          onRequest: (options, handler) async {
            // 保存特定请求的请求头(通过 options.headers 传递的,优先级最高)
            final specificHeaders =
                Map<String, dynamic>.from(options.headers);

            // 先添加静态请求头(优先级最低)
            if (_config!.staticHeaders != null) {
              options.headers.addAll(_config!.staticHeaders!);
            }

            // 再添加动态请求头(优先级中等)
            if (_config!.dynamicHeaderBuilder != null) {
              final dynamicHeaders = await _config!.dynamicHeaderBuilder!();
              options.headers.addAll(dynamicHeaders);
            }

            // 最后添加特定请求头(优先级最高,会覆盖全局请求头)
            options.headers.addAll(specificHeaders);

            return handler.next(options);
          },
          onResponse: (response, handler) {
            // 处理 401 错误(未授权)
            // 注意:这里不直接清除登录信息,而是通过回调通知外部
            // 外部可以通过 dynamicHeaderBuilder 返回空的 Authorization 来实现清除
            return handler.next(response);
          },
          onError: (error, handler) {
            // 只处理网络错误等其他错误,HTTP 错误状态码已经在 onResponse 中处理
            return handler.next(error);
          },
        ),
      );

      // 后添加日志拦截器(这样可以看到完整的 headers)
      if (_config!.enableLogging) {
        _dioInstance!.interceptors.add(
          LogInterceptor(
            printBody: _config!.logPrintBody,
            logMode: _config!.logMode,
            showRequestHint: _config!.logShowRequestHint,
          ),
        );
      }
    }
  }
  return _dioInstance!;
}