在 Flutter 中使用 Dio 封装网络请求时,通常需要暴露以下内容:
- 常用 HTTP 方法(GET/POST/PUT/DELETE)
- 请求配置(基础 URL、超时时间等)
- 错误统一处理
- 拦截器(日志、token 处理)
- 请求取消能力
以下是完整封装示例:
dart
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
class HttpUtil {
static final HttpUtil _instance = HttpUtil._internal();
late Dio dio;
final CancelToken _cancelToken = CancelToken();
factory HttpUtil() => _instance;
HttpUtil._internal() {
// Base配置
BaseOptions options = BaseOptions(
connectTimeout: const Duration(seconds: 15),
receiveTimeout: const Duration(seconds: 15),
sendTimeout: const Duration(seconds: 10),
responseType: ResponseType.json,
);
dio = Dio(options);
// 添加拦截器
dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) {
// 请求前添加token
options.headers['Authorization'] = 'Bearer your_token';
return handler.next(options);
},
onResponse: (response, handler) {
// 统一处理响应数据
if (response.data['code'] != 200) {
return handler.reject(
DioException(
requestOptions: response.requestOptions,
error: response.data['msg'],
response: response,
),
);
}
return handler.next(response);
},
onError: (DioException e, handler) async {
// 统一错误处理
if (e.response?.statusCode == 401) {
// token过期处理
// await refreshToken();
// return _retry(e.requestOptions);
}
return handler.next(e);
},
));
// 调试模式下添加日志拦截器
if (kDebugMode) {
dio.interceptors.add(LogInterceptor(
responseBody: true,
requestHeader: true,
responseHeader: false,
request: false,
));
}
}
/// 封装GET请求
Future<dynamic> get(
String path, {
Map<String, dynamic>? params,
Options? options,
CancelToken? cancelToken,
}) async {
try {
Response response = await dio.get(
path,
queryParameters: params,
options: options,
cancelToken: cancelToken ?? _cancelToken,
);
return response.data;
} on DioException catch (e) {
_handleError(e);
rethrow;
}
}
/// 封装POST请求
Future<dynamic> post(
String path, {
dynamic data,
Map<String, dynamic>? params,
Options? options,
CancelToken? cancelToken,
}) async {
try {
Response response = await dio.post(
path,
data: data,
queryParameters: params,
options: options,
cancelToken: cancelToken ?? _cancelToken,
);
return response.data;
} on DioException catch (e) {
_handleError(e);
rethrow;
}
}
// 统一错误处理
void _handleError(DioException e) {
String errorMsg = '网络请求异常';
if (e.type == DioExceptionType.connectionTimeout) {
errorMsg = '连接超时';
} else if (e.type == DioExceptionType.receiveTimeout) {
errorMsg = '接收超时';
} else if (e.type == DioExceptionType.sendTimeout) {
errorMsg = '发送超时';
} else if (e.type == DioExceptionType.badResponse) {
errorMsg = '服务器异常:${e.response?.statusCode}';
} else if (e.type == DioExceptionType.cancel) {
errorMsg = '请求已取消';
}
debugPrint('HTTP Error: $errorMsg');
// 这里可以添加全局错误提示,比如显示SnackBar
}
/// 取消所有请求
void cancelRequests() {
_cancelToken.cancel('手动取消请求');
}
/// 设置基础URL
void setBaseUrl(String url) {
dio.options.baseUrl = url;
}
/// 更新授权token
void updateToken(String token) {
dio.options.headers['Authorization'] = 'Bearer $token';
}
}
使用示例:
dart
// 初始化(通常在main函数中)
final http = HttpUtil();
http.setBaseUrl('https://api.example.com/v1/');
// GET请求示例
void fetchData() async {
try {
final response = await http.get('user/profile');
print(response);
} catch (e) {
print('请求失败: $e');
}
}
// POST请求示例
void postData() async {
try {
final response = await http.post(
'user/login',
data: {'email': 'test@example.com', 'password': '123456'},
);
print(response);
} catch (e) {
print('登录失败: $e');
}
}
// 取消请求示例
CancelToken cancelToken = CancelToken();
http.get('big-data', cancelToken: cancelToken).catchError((e){
if (CancelToken.isCancel(e)) {
print('请求被取消: ${e.message}');
}
});
// 需要取消时调用
cancelToken.cancel('用户主动取消');
主要封装特点:
-
单例模式:确保全局使用同一个Dio实例
-
统一配置:超时时间、基础URL等集中管理
-
拦截器链:
- 自动添加认证Token
- 响应状态码统一处理
- 调试日志输出
-
错误处理:
- 网络超时分类处理
- 服务器错误代码处理
- 请求取消处理
-
扩展能力:
- 支持自定义取消Token
- 动态更新基础URL
- 方便添加其他HTTP方法(PUT/DELETE等)
可以根据实际需求添加以下功能:
- 文件上传/下载进度回调
- 请求重试机制
- 更复杂的缓存策略
- 连接状态监测
- 响应数据自动序列化(配合json_serializable)