3步打造Dio自定义拦截器:告别重复请求与冗余代码
Dio是Dart和Flutter中强大的HTTP客户端,支持全局设置、拦截器、FormData、请求取消、文件上传下载等功能。拦截器作为Dio的核心特性,能够在请求/响应生命周期中处理请求配置、响应数据和错误信息,帮助开发者告别重复请求与冗余代码,提升应用性能与可维护性。## 一、Dio拦截器基础:拦截器的核心价值与工作原理Dio拦截器通过拦截请求、响应和错误三种关键节点,实现对HTTP通
3步打造Dio自定义拦截器:告别重复请求与冗余代码
Dio是Dart和Flutter中强大的HTTP客户端,支持全局设置、拦截器、FormData、请求取消、文件上传下载等功能。拦截器作为Dio的核心特性,能够在请求/响应生命周期中处理请求配置、响应数据和错误信息,帮助开发者告别重复请求与冗余代码,提升应用性能与可维护性。
一、Dio拦截器基础:拦截器的核心价值与工作原理
Dio拦截器通过拦截请求、响应和错误三种关键节点,实现对HTTP通信的全面控制。拦截器本质上是一个实现了Interceptor抽象类的对象,包含三个核心方法:
- 请求拦截(onRequest):在请求发送前修改配置(如添加Token、设置超时)
- 响应拦截(onResponse):在响应返回后处理数据(如统一解析、错误转换)
- 错误拦截(onError):在请求失败时捕获异常(如网络错误重试、登录失效处理)
Dio框架提供了两种拦截器类型:基础拦截器(Interceptor)和队列拦截器(QueuedInterceptor)。队列拦截器会将并发请求放入队列顺序执行,适合需要严格控制请求顺序的场景(如Token刷新)。
二、第1步:创建基础拦截器——从理论到实践
2.1 基础拦截器实现模板
创建自定义拦截器最简单的方式是使用InterceptorsWrapper,它允许你按需实现拦截方法:
import 'package:dio/dio.dart';
class CustomInterceptor extends InterceptorsWrapper {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
// 请求发送前处理
print('请求URL: ${options.uri}');
handler.next(options); // 必须调用next()将请求传递给下一个拦截器
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
// 响应返回后处理
print('响应状态码: ${response.statusCode}');
handler.next(response);
}
@override
void onError(DioException err, ErrorInterceptorHandler handler) {
// 错误处理
print('请求错误: ${err.message}');
handler.next(err);
}
}
2.2 注册拦截器到Dio实例
创建拦截器后,通过dio.interceptors.add()方法将其添加到Dio实例:
final dio = Dio();
dio.interceptors.add(CustomInterceptor());
Dio默认包含一个ImplyContentTypeInterceptor,用于自动推断请求内容类型。如需移除默认拦截器,可调用:
dio.interceptors.removeImplyContentTypeInterceptor();
三、第2步:实现实用拦截器——解决实际开发痛点
3.1 日志拦截器:调试请求的得力助手
Dio内置的LogInterceptor可打印请求/响应详情,是开发调试的必备工具。通过配置参数可控制日志输出内容:
dio.interceptors.add(LogInterceptor(
requestBody: true, // 打印请求体
responseBody: true, // 打印响应体
logPrint: print, // 自定义日志输出方式(Flutter中建议使用debugPrint)
));
3.2 防重复请求拦截器:优化用户体验
通过记录请求标识(如URL+参数),在请求未完成时阻止重复发送:
class AntiDuplicateInterceptor extends InterceptorsWrapper {
final Set<String> _requestIds = {};
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
final requestId = '${options.method}-${options.uri}';
if (_requestIds.contains(requestId)) {
// 取消重复请求
handler.reject(DioException(
requestOptions: options,
type: DioExceptionType.cancel,
message: '重复请求已拦截',
));
} else {
_requestIds.add(requestId);
handler.next(options);
}
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
_removeRequestId(response.requestOptions);
handler.next(response);
}
@override
void onError(DioException err, ErrorInterceptorHandler handler) {
_removeRequestId(err.requestOptions);
handler.next(err);
}
void _removeRequestId(RequestOptions options) {
final requestId = '${options.method}-${options.uri}';
_requestIds.remove(requestId);
}
}
四、第3步:高级拦截器技巧——队列拦截器与拦截器链
4.1 队列拦截器:处理并发请求依赖
当需要确保拦截器按顺序执行(如Token刷新后才能发送其他请求),可使用QueuedInterceptorsWrapper:
class TokenRefreshInterceptor extends QueuedInterceptorsWrapper {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
if (_needRefreshToken()) {
await _refreshToken(); // 等待Token刷新完成
}
options.headers['Authorization'] = 'Bearer $_token';
handler.next(options);
}
}
4.2 拦截器链:组合多个拦截器
Dio支持添加多个拦截器形成拦截器链,执行顺序与添加顺序一致:
dio.interceptors.addAll([
LogInterceptor(), // 日志拦截器(先执行)
AntiDuplicateInterceptor(),// 防重复拦截器
TokenRefreshInterceptor(), // Token拦截器(后执行)
]);
注意:拦截器执行顺序遵循FIFO原则,日志拦截器建议放在最后,以捕获其他拦截器的修改结果。
五、拦截器最佳实践与注意事项
- 单一职责原则:每个拦截器只处理一种逻辑(如日志、Token、缓存分离)
- 避免阻塞:耗时操作(如Token刷新)应使用异步处理
- 错误处理:确保每个拦截器正确调用
handler.next()或handler.reject() - 调试技巧:使用
LogInterceptor追踪拦截器执行过程 - 性能考量:避免在拦截器中执行复杂计算或IO操作
通过合理使用拦截器,你可以将通用HTTP逻辑(如认证、日志、缓存)与业务代码解耦,显著提升项目的可维护性。Dio的拦截器机制为开发者提供了灵活而强大的请求处理能力,是构建健壮网络层的关键工具。
更多推荐

所有评论(0)