flutter_integrated_whb/lib/http/HttpManager.dart

172 lines
4.9 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import 'dart:io';
import 'dart:ui';
import 'package:dio/dio.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/tools/tools.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) {
// TODO 暂不处理
// 捕获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<Map<String, dynamic>> request(
String baseUrl,
String path, {
Method method = Method.post,
Map<String, dynamic>? data,
Map<String, dynamic>? params,
CancelToken? cancelToken,
bool withToken = false, // 新增可选参数,默认 false
}) async {
Response resp;
final url = baseUrl + path;
// 动态 headers
final headers = {
'Content-Type': Headers.formUrlEncodedContentType,
};
if (withToken) {
final token = SessionService.instance.studyToken;
if (token != null && token.isNotEmpty) {
headers['Token'] = token;
}
}
final options = Options(
method: method.name.toUpperCase(),
contentType: Headers.formUrlEncodedContentType,
headers: headers,
);
try {
switch (method) {
case Method.get:
resp = await _dio.get(url,
queryParameters: {...?params, ...?data},
cancelToken: cancelToken,
options: options);
break;
case Method.post:
resp = await _dio.post(url,
data: data,
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;
}
} on DioException catch (e) {
if (e.error is ApiException) throw e.error as ApiException;
throw ApiException('network_error', e.message ?? e.toString());
}
final json = resp.data is Map<String, dynamic>
? resp.data as Map<String, dynamic>
: <String, dynamic>{};
return json;
}
}
/// 上传图片扩展
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) {
// 如果已经是ApiException类型401转换的
if (e.error is ApiException) {
throw e.error as ApiException;
}
throw ApiException('network_error', e.message ?? e.toString());
}
}
}