flutter_integrated_whb/lib/http/HttpManager.dart

174 lines
4.9 KiB
Dart
Raw Normal View History

2025-07-17 16:10:46 +08:00
import 'dart:io';
2025-07-18 17:13:38 +08:00
import 'dart:ui';
2025-07-15 08:32:50 +08:00
import 'package:dio/dio.dart';
2025-07-17 16:10:46 +08:00
/// 全局接口异常
2025-07-15 08:32:50 +08:00
class ApiException implements Exception {
final String result;
final String message;
ApiException(this.result, this.message);
2025-07-18 17:13:38 +08:00
2025-07-15 08:32:50 +08:00
@override
String toString() => 'ApiException($result): $message';
}
/// HTTP 方法枚举
enum Method { get, post, put, delete }
2025-07-17 16:10:46 +08:00
/// HTTP 管理器 单例
2025-07-15 08:32:50 +08:00
class HttpManager {
HttpManager._internal() {
_dio = Dio(BaseOptions(
connectTimeout: const Duration(milliseconds: 10000),
receiveTimeout: const Duration(milliseconds: 10000),
headers: {
2025-07-17 16:10:46 +08:00
'Content-Type': Headers.formUrlEncodedContentType,
2025-07-15 08:32:50 +08:00
},
));
_initInterceptors();
}
static final HttpManager _instance = HttpManager._internal();
factory HttpManager() => _instance;
late final Dio _dio;
2025-07-18 17:13:38 +08:00
// 添加401处理回调
static VoidCallback? onUnauthorized;
2025-07-15 08:32:50 +08:00
void _initInterceptors() {
_dio.interceptors
..add(LogInterceptor(request: true, responseBody: true, error: true))
..add(InterceptorsWrapper(onError: (err, handler) {
2025-07-22 13:34:34 +08:00
// TODO 暂不处理
2025-07-18 17:13:38 +08:00
// 捕获401错误
2025-07-22 13:34:34 +08:00
// if (err.response?.statusCode == 401) {
// // 触发全局登出回调
// onUnauthorized?.call();
// // 创建自定义异常
// final apiException = ApiException(
// '提示',
// '您的账号已在其他设备登录,已自动下线'
// );
// // 直接抛出业务异常,跳过后续错误处理
// return handler.reject(
// DioException(
// requestOptions: err.requestOptions,
// error: apiException,
// response: err.response,
// type: DioExceptionType.badResponse,
// ),
// );
// }
2025-07-15 08:32:50 +08:00
handler.next(err);
}));
}
2025-07-17 16:10:46 +08:00
/// 通用请求方法,返回完整后台 JSON
2025-07-15 08:32:50 +08:00
Future<Map<String, dynamic>> request(
String baseUrl,
String path, {
Method method = Method.post,
Map<String, dynamic>? data,
Map<String, dynamic>? params,
CancelToken? cancelToken,
}) async {
Response resp;
final url = baseUrl + path;
final options = Options(
method: method.name.toUpperCase(),
contentType: Headers.formUrlEncodedContentType,
);
2025-07-17 16:10:46 +08:00
2025-07-15 08:32:50 +08:00
try {
switch (method) {
case Method.get:
2025-07-17 16:10:46 +08:00
resp = await _dio.get(
url,
queryParameters: params,
cancelToken: cancelToken,
options: options,
);
2025-07-15 08:32:50 +08:00
break;
case Method.put:
2025-07-17 16:10:46 +08:00
resp = await _dio.put(
url,
data: data,
queryParameters: params,
cancelToken: cancelToken,
options: options,
);
2025-07-15 08:32:50 +08:00
break;
case Method.delete:
2025-07-17 16:10:46 +08:00
resp = await _dio.delete(
url,
queryParameters: params,
cancelToken: cancelToken,
options: options,
);
2025-07-15 08:32:50 +08:00
break;
case Method.post:
2025-07-18 17:13:38 +08:00
resp = await _dio.post(
2025-07-17 16:10:46 +08:00
url,
data: data,
queryParameters: params,
cancelToken: cancelToken,
options: options,
);
2025-07-15 08:32:50 +08:00
}
2025-07-17 16:10:46 +08:00
} on DioException catch (e) {
2025-07-18 17:13:38 +08:00
// 如果已经是ApiException类型401转换的
if (e.error is ApiException) {
throw e.error as ApiException;
}
// 其他网络错误
2025-07-17 16:10:46 +08:00
throw ApiException('network_error', e.message ?? e.toString());
2025-07-15 08:32:50 +08:00
}
// 解析返回 JSON
final json = resp.data is Map<String, dynamic>
? resp.data as Map<String, dynamic>
: <String, dynamic>{};
final result = json['result'] as String?;
final msg = json['msg'] as String? ?? json['message'] as String? ?? '';
2025-07-31 21:15:00 +08:00
// if (result != 'success') {
// // 非 success 都抛异常
// throw ApiException(result ?? 'unknown', msg);
// }
2025-07-15 08:32:50 +08:00
return json;
}
}
2025-07-17 16:10:46 +08:00
/// 上传图片扩展
extension HttpManagerUpload on HttpManager {
Future<Map<String, dynamic>> uploadFaceImage({
required String baseUrl,
required String path,
required Map<String, dynamic> fromData,
CancelToken? cancelToken,
}) async {
final form = FormData.fromMap(fromData);
try {
final resp = await _dio.post(
baseUrl + path,
data: form,
cancelToken: cancelToken,
options: Options(
method: Method.post.name.toUpperCase(),
contentType: 'multipart/form-data',
),
);
final json = resp.data is Map<String, dynamic>
? resp.data as Map<String, dynamic>
: <String, dynamic>{};
return json;
} on DioException catch (e) {
2025-07-18 17:13:38 +08:00
// 如果已经是ApiException类型401转换的
if (e.error is ApiException) {
throw e.error as ApiException;
}
2025-07-17 16:10:46 +08:00
throw ApiException('network_error', e.message ?? e.toString());
}
}
2025-07-18 17:13:38 +08:00
}