import 'dart:io'; import 'dart:ui'; import 'package:dio/dio.dart'; /// 全局接口异常 class ApiException implements Exception { final String result; final String message; ApiException(this.result, this.message); @override String toString() => 'ApiException($result): $message'; } /// HTTP 方法枚举 enum Method { get, post, put, delete } /// HTTP 管理器 单例 class HttpManager { HttpManager._internal() { _dio = Dio(BaseOptions( connectTimeout: const Duration(milliseconds: 10000), receiveTimeout: const Duration(milliseconds: 10000), headers: { 'Content-Type': Headers.formUrlEncodedContentType, }, )); _initInterceptors(); } static final HttpManager _instance = HttpManager._internal(); factory HttpManager() => _instance; late final Dio _dio; // 添加401处理回调 static VoidCallback? onUnauthorized; void _initInterceptors() { _dio.interceptors ..add(LogInterceptor(request: true, responseBody: true, error: true)) ..add(InterceptorsWrapper(onError: (err, handler) { // 捕获401错误 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, ), ); } handler.next(err); })); } /// 通用请求方法,返回完整后台 JSON Future> request( String baseUrl, String path, { Method method = Method.post, Map? data, Map? params, CancelToken? cancelToken, }) async { Response resp; final url = baseUrl + path; final options = Options( method: method.name.toUpperCase(), contentType: Headers.formUrlEncodedContentType, ); try { switch (method) { case Method.get: resp = await _dio.get( url, queryParameters: params, cancelToken: cancelToken, options: options, ); break; case Method.put: resp = await _dio.put( url, data: data, queryParameters: params, cancelToken: cancelToken, options: options, ); break; case Method.delete: resp = await _dio.delete( url, queryParameters: params, cancelToken: cancelToken, options: options, ); break; case Method.post: resp = await _dio.post( url, data: data, queryParameters: params, cancelToken: cancelToken, options: options, ); } } on DioException catch (e) { // 如果已经是ApiException类型(401转换的) if (e.error is ApiException) { throw e.error as ApiException; } // 其他网络错误 throw ApiException('network_error', e.message ?? e.toString()); } // 解析返回 JSON final json = resp.data is Map ? resp.data as Map : {}; final result = json['result'] as String?; final msg = json['msg'] as String? ?? json['message'] as String? ?? ''; if (result != 'success') { // 非 success 都抛异常 throw ApiException(result ?? 'unknown', msg); } return json; } } /// 上传图片扩展 extension HttpManagerUpload on HttpManager { Future> uploadFaceImage({ required String baseUrl, required String path, required Map 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 ? resp.data as Map : {}; return json; } on DioException catch (e) { // 如果已经是ApiException类型(401转换的) if (e.error is ApiException) { throw e.error as ApiException; } throw ApiException('network_error', e.message ?? e.toString()); } } }