Flutter dio http 封装指南说明
'# Flutter dio http 封装指南说明
一、背景与问题
在Flutter开发中,网络请求是每个应用的刚需功能。原始的http库虽然功能完备,但存在以下痛点:
- 重复代码:每个请求都需要重复编写headers设置、错误处理、超时控制等逻辑
- 缺乏统一管理:难以集中管理API地址、请求参数、响应格式等
- 错误处理不统一:不同接口的错误处理逻辑差异大
- 缺乏拦截能力:无法统一处理请求/响应数据,无法实现日志记录、请求重试等功能
Dio作为基于Dart的高性能HTTP客户端,提供了更强大的功能,但直接使用仍存在封装成本。我们需要通过合理的封装设计,实现以下目标:
- 统一网络请求接口
- 自动处理JSON解析
- 统一错误处理
- 支持请求重试
- 提供文件上传/下载能力
- 支持网络状态监听
二、基本原理
Dio基于Dart的HttpClient实现,通过以下核心机制实现灵活的网络请求:
1. 拦截器系统
Dio提供了Interceptor机制,允许在请求发送前和响应接收后进行拦截处理:
Dio dio = Dio();
dio.interceptors.add(Interceptors());每个拦截器包含onSend和onResponse回调,可以实现:
- 请求参数的统一处理(如添加token)
- 请求日志记录
- 响应数据的统一格式化
- 错误处理和重试机制
2. 响应处理机制
Dio默认将响应数据自动解析为Response<T>对象,支持以下特性:
- 自动解析JSON
- 支持
data、headers、status等字段 - 可自定义解析逻辑(通过
responseAdapter)
3. 请求重试机制
通过Retry类可以实现自动重试功能,支持:
- 重试次数限制
- 重试间隔时间
- 重试条件判断(如网络错误)
三、环境准备
在pubspec.yaml中添加依赖:
dependencies:
dio: ^5.0.0
flutter_secure_storage: ^5.0.0安装完成后,需要在main.dart中初始化:
import 'package:dio/dio.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
final storage = FlutterSecureStorage();四、核心实现
1. 基础封装类
class ApiClient {
final Dio _dio = Dio();
ApiClient() {
_initDio();
}
void _initDio() {
_dio.options = BaseOptions(
baseUrl: 'https://api.example.com',
timeout: 10000,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
);
_dio.interceptors.add(Interceptors());
}
Future<Response<T>> get<T>(String path, {Map<String, dynamic>? queryParameters}) async {
try {
final response = await _dio.get<T>(path, queryParameters: queryParameters);
return response;
} catch (e) {
throw Exception('Request failed: $e');
}
}
}关键代码解释:
BaseOptions配置了基础URL、超时时间、headersinterceptors.add(Interceptors())添加了拦截器get方法封装了通用的GET请求
2. 拦截器实现
class Interceptors extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
// 添加请求日志
print('Request: ${options.path} - ${options.method}');
// 添加认证token
final token = await getToken();
if (token != null) {
options.headers['Authorization'] = 'Bearer $token';
}
// 执行后续拦截器
handler.next(options);
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
// 处理响应数据
if (response.data is Map) {
response.data = response.data['data'];
}
// 执行后续拦截器
handler.next(response);
}
Future<String?> getToken() async {
final storage = FlutterSecureStorage();
return await storage.read(key: 'token');
}
}关键代码解释:
onRequest处理请求前逻辑onResponse处理响应后逻辑- 从secure storage中读取token
3. 错误处理封装
Future<void> handleResponse<T>(Response<T> response) async {
if (response.statusCode! >= 200 && response.statusCode! < 300) {
return response.data;
} else {
throw Exception('Server error: ${response.statusMessage}');
}
}关键代码解释:
- 检查HTTP状态码
- 抛出统一的异常
五、完整案例
1. 用户登录接口封装
class AuthApi {
final ApiClient _apiClient = ApiClient();
Future<void> login(String username, String password) async {
final response = await _apiClient.get('/login', queryParameters: {
'username': username,
'password': password,
});
if (response.data is Map) {
final token = response.data['token'];
if (token != null) {
await _saveToken(token);
}
}
}
Future<void> _saveToken(String token) async {
final storage = FlutterSecureStorage();
await storage.write(key: 'token', value: token);
}
}2. 网络状态监听
class NetworkMonitor {
final Connectivity _connectivity = Connectivity();
Future<void> checkNetworkStatus() async {
final status = await _connectivity.checkConnectivity();
if (status == ConnectivityResult.none) {
// 处理无网络情况
}
}
}3. 文件上传封装
Future<Response> uploadFile(String filePath, String uploadUrl) async {
final dio = Dio();
final response = await dio.post(
uploadUrl,
data: await MultipartFile.fromFile(filePath),
options: Options(
headers: {'Content-Type': 'multipart/form-data'},
),
);
return response;
}六、源码解析
1. 拦截器执行流程
Dio的拦截器按添加顺序执行,执行流程如下:
onRequest处理- 执行后续拦截器
- 发送请求
- 接收响应
onResponse处理- 执行后续拦截器
2. 错误处理机制
Dio的错误处理分为两种:
- 网络错误(如超时、DNS解析失败)
- 业务错误(如HTTP 401、500)
通过onError回调可处理网络错误:
dio.interceptors.add(Interceptor(
onError: (DioException error, ErrorInterceptorHandler handler) {
print('Error: ${error.message}');
handler.next(error);
},
));七、进阶使用
1. 自动重试机制
class RetryInterceptor extends Interceptor {
@override
void onError(DioException error, ErrorInterceptorHandler handler) {
if (error.response?.statusCode == 503) {
// 服务不可用时重试
handler.retriesLeft -= 1;
if (handler.retriesLeft > 0) {
handler.next(error);
}
}
}
}2. 请求缓存机制
final cache = Cache();
Future<Response<T>> getWithCache<T>(String path, {Map<String, dynamic>? queryParameters}) async {
final key = '$path?${queryParameters?.toString()}';
final cached = await cache.get(key);
if (cached != null) {
return cached;
}
final response = await _apiClient.get(path, queryParameters: queryParameters);
await cache.set(key, response);
return response;
}3. 接口分组管理
class ApiGroup {
final String name;
final List<ApiEndpoint> endpoints;
ApiGroup({required this.name, required this.endpoints});
}八、性能与工程实践
1. 性能优化策略
| 优化策略 | 实现方式 | 效果 |
|---|---|---|
| HTTP/2支持 | 使用HttpClient的useHttp2 | 减少请求延迟 |
| 连接复用 | 使用ConnectionPool | 降低建立新连接的开销 |
| 响应压缩 | 设置Accept-Encoding | 减少传输数据量 |
| 缓存策略 | 使用内存缓存和本地缓存 | 减少网络请求 |
2. 安全实践
- HTTPS强制:配置
BaseOptions强制使用HTTPS - Token安全:使用
flutter_secure_storage保存敏感信息 - CSRF防护:在请求头中添加
X-CSRF-Token字段 - 数据加密:对敏感数据进行AES加密处理
3. 异常处理规范
- 网络错误:返回
NetworkException - 业务错误:返回
BusinessException - 系统错误:返回
SystemException
九、常见问题与踩坑
1. 拦截器未生效
原因:未正确配置Dio实例,或者拦截器未被添加到interceptors列表
解决:确保在创建Dio实例后调用interceptors.add()方法
2. 错误处理不统一
原因:未统一处理DioException,导致错误信息不一致
解决:统一使用try/catch块捕获异常,使用handleResponse方法统一处理响应
3. 文件上传失败
原因:未正确设置Content-Type头,或者未使用MultipartFile
解决:使用MultipartFile.fromFile(),并设置multipart/form-data内容类型
4. 重试机制失效
原因:未正确配置Retry参数,或者未处理DioException
解决:在onError回调中处理重试逻辑,设置retriesLeft参数
十、最佳实践
- 统一网络层:将所有网络请求集中到
ApiClient类中 - 分离业务逻辑:将接口调用与业务处理分离,提高可维护性
- 使用依赖注入:通过
getIt等库实现依赖注入,提高可测试性 - 接口分组管理:按功能模块划分接口,提高可维护性
- 错误分类处理:根据错误类型进行不同的处理逻辑
- 性能监控:记录网络请求耗时,监控关键接口性能
- 安全防护:强制使用HTTPS,对敏感数据进行加密处理
十一、总结
通过合理的Dio封装设计,可以显著提升Flutter应用的网络请求质量。本文深入解析了Dio的底层机制,展示了如何通过拦截器、错误处理、重试机制等实现统一的网络请求管理。在实际开发中,需要根据具体业务需求选择合适的封装策略,合理处理网络异常、数据安全、性能优化等问题。
在开发过程中需要注意以下几点:
- 避免过度封装,保持接口的灵活性
- 根据业务需求选择合适的重试策略
- 对敏感数据进行加密处理
- 记录详细的网络请求日志
- 定期进行性能监控和优化
通过合理的封装和实践,可以显著提升应用的稳定性和可维护性,为后续的功能扩展打下坚实基础。
评论已关闭