设计方案
- 全局拦截器:
- 日志记录:创建一个全局日志拦截器,在请求发送前和响应接收后记录详细日志,方便排查问题。例如:
class LoggingInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
print('Request URL: ${options.uri}');
print('Request Headers: ${options.headers}');
print('Request Body: ${options.data}');
return handler.next(options);
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
print('Response Status Code: ${response.statusCode}');
print('Response Data: ${response.data}');
return handler.next(response);
}
@override
void onError(DioError err, ErrorInterceptorHandler handler) {
print('Error: ${err.message}');
return handler.next(err);
}
}
- **通用Header设置**:添加一个拦截器用于设置所有请求通用的Header,如认证Token等。
class CommonHeaderInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
options.headers['Authorization'] = 'Bearer your_token';
return handler.next(options);
}
}
- 模块级拦截器:
- 请求频率控制:对于请求频率较高的模块,使用
Dio
的Interceptors
实现请求频率限制。例如,使用一个计数器和时间记录来确保在一定时间内请求次数不超过设定值。
class RateLimitInterceptor extends Interceptor {
final int requestsPerSecond;
final Map<String, int> requestCounts = {};
final Map<String, DateTime> lastRequestTimes = {};
RateLimitInterceptor(this.requestsPerSecond);
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
final key = options.uri.toString();
if (!requestCounts.containsKey(key)) {
requestCounts[key] = 1;
lastRequestTimes[key] = DateTime.now();
return handler.next(options);
}
final elapsedTime = DateTime.now().difference(lastRequestTimes[key]!).inSeconds;
if (elapsedTime >= 1) {
requestCounts[key] = 1;
lastRequestTimes[key] = DateTime.now();
return handler.next(options);
} else if (requestCounts[key]! < requestsPerSecond) {
requestCounts[key] = requestCounts[key]! + 1;
return handler.next(options);
} else {
// 达到频率限制,等待一段时间
Future.delayed(Duration(seconds: 1 - elapsedTime)).then((_) {
requestCounts[key] = 1;
lastRequestTimes[key] = DateTime.now();
handler.resume(RequestOptions(replace: options));
});
}
}
}
- **特定模块响应处理**:每个模块可以有自己的响应拦截器,根据模块需求处理响应。例如,某些模块可能需要对特定的响应状态码进行统一处理。
class ModuleSpecificResponseInterceptor extends Interceptor {
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
if (response.statusCode == 401) {
// 处理模块特定的401错误,如重新登录等
}
return handler.next(response);
}
}
- 错误处理拦截器:
- 统一错误处理:创建一个全局错误处理拦截器,捕获所有请求的错误,根据错误类型进行不同处理,如显示友好的错误提示给用户。
class GlobalErrorInterceptor extends Interceptor {
@override
void onError(DioError err, ErrorInterceptorHandler handler) {
if (err.type == DioErrorType.connectTimeout) {
// 处理连接超时错误
} else if (err.type == DioErrorType.receiveTimeout) {
// 处理接收超时错误
}
return handler.next(err);
}
}
优化策略
- 复用Dio实例:在整个项目中尽量复用同一个
Dio
实例,避免频繁创建和销毁Dio
实例带来的性能开销。
- 异步处理:在拦截器的响应和错误处理中,尽量使用异步操作,避免阻塞主线程。例如,在处理复杂的响应数据解析或错误处理逻辑时,可以使用
compute
等方法在隔离的 isolate 中执行。
- 内存管理:
- 及时释放资源:在拦截器处理完响应或错误后,确保及时释放不再使用的资源,如关闭流、释放缓存等。
- 避免内存泄漏:注意在拦截器中使用的闭包和回调函数,确保它们不会持有对不需要的对象的引用,防止内存泄漏。例如,在使用
Stream
时,确保正确订阅和取消订阅,避免内存泄漏。
- 缓存策略:对于一些不经常变化的数据请求,可以在拦截器中实现缓存策略。例如,使用
Dio
的CacheManager
,在请求前检查缓存,如果缓存存在且未过期,则直接返回缓存数据,减少网络请求。
import 'package:dio_cache_interceptor/dio_cache_interceptor.dart';
final dio = Dio()
..interceptors.add(
DioCacheInterceptor(
options: CacheOptions(
store: MemCacheStore(),
policy: CachePolicy.requestFresh,
maxStale: const Duration(days: 7),
),
),
);