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!;
}