import 'dart:async'; import 'dart:io'; import 'package:dio/dio.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:aslan/chatvibe_core/utilities/at_loading_manager.dart'; import 'package:aslan/chatvibe_data/sources/local/user_manager.dart'; import 'package:aslan/chatvibe_core/constants/at_global_config.dart'; import 'package:aslan/chatvibe_core/utilities/at_deviceId_utils.dart'; import 'package:aslan/chatvibe_data/sources/remote/net/api.dart'; import 'package:aslan/chatvibe_data/sources/remote/net/at_logger.dart'; NetworkClient get http => _httpInstance; bool inLoginPage = false; late final NetworkClient _httpInstance = NetworkClient(); class NetworkClient extends BaseNetworkClient { @override void init() { // 设置基础URL dio.options.baseUrl = ATGlobalConfig.apiHost; // 添加拦截器 dio.interceptors ..add(ApiInterceptor()) ..add(ATDioLogger()) ..add(TimeOutInterceptor()); setupCacheInterceptor(dio); // 传入 dio 实例 } Future setupCacheInterceptor(Dio dio) async { // 缓存配置保持不变... } } class ApiInterceptor extends Interceptor { @override void onRequest( RequestOptions options, RequestInterceptorHandler handler, ) async { // 确保使用最新的 baseUrl options.baseUrl = ATGlobalConfig.apiHost; String token = AccountStorage().getToken(); var imei = await ATDeviceIdUtils.collectDeviceId(); Map headMap = {}; headMap["req-lang"] = ATGlobalConfig.lang; headMap["X-Forwarded-Proto"] = "http"; headMap["User-Agent"] = "Dart/3.7.2(dart:io)"; headMap["req-imei"] = imei; headMap["Host"] = options.uri.host; headMap["req-app-intel"] = "version=${ATGlobalConfig.version};build=${ATGlobalConfig.build};model=${ATGlobalConfig.model};sysVersion=${ATGlobalConfig.sysVersion};channel=${ATGlobalConfig.channel}"; headMap["req-client"] = Platform.isAndroid ? 'Android' : 'iOS'; headMap["req-sys-origin"] = "origin=${ATGlobalConfig.origin};originChild=${ATGlobalConfig.originChild}"; if (token.isNotEmpty) { headMap["Authorization"] = "Bearer $token"; } ///加密 headMap["Req-Atyou"] = true; options.headers.addAll(headMap); handler.next(options); } @override void onResponse(Response response, ResponseInterceptorHandler handler) async { if (response.statusCode == 200) { final ResponseData respData = ResponseData.fromJson(response.data); if (respData.success) { handler.next(response); } else { // if (respData.code == 210||respData.code == 212) { // 登录失效 // if (!inLoginPage) { // Fluttertoast.showToast(msg: respData.msg ?? "需要重新登录"); // SpUtils.sp?.clear(); // navigatorKey.currentState?.pushAndRemoveUntil( // MaterialPageRoute(builder: (_) { // Provider.of(_, listen: false).destoryRtm(); // Provider.of(_, listen: false).logout(); // Provider.of(_, listen: false).engine?.leaveChannel(); // return const LoginPage(); // }), // (route) => false // 清除所有路由 // ); // // inLoginPage = true; // } // } else { // Fluttertoast.showToast(msg: respData.msg ?? "操作失败"); // } // 使用 DioException 传递错误 handler.reject( DioException( requestOptions: response.requestOptions, error: NotSuccessException.fromRespData(respData), response: response, message: respData.errorMsg, ), ); } } else { Fluttertoast.showToast(msg: 'Network error, please check the status.'); handler.reject( DioException( requestOptions: response.requestOptions, error: 'HTTP ${response.statusCode} 错误', response: response, ), ); } } } /// 响应数据结构 class ResponseData { final bool status; final int? errorCode; final String? errorCodeName; final String? errorMsg; final T? body; final num? time; bool get success => status; ResponseData({ required this.status, this.errorCode, this.errorCodeName, this.errorMsg, this.body, this.time, }); // 特殊处理基础类型 static T? _parseData(dynamic data, T Function(dynamic) fromJsonT) { if (data == null) return null; // 布尔值特殊处理 if (T == bool) { if (data is bool) return data as T; if (data is int) return (data != 0) as T; if (data is String) return (data.toLowerCase() == 'true') as T; } // 其他基础类型 if (T == int || T == double || T == String || T == bool) { return data as T; } // 复杂类型使用转换函数 return fromJsonT(data); } factory ResponseData.fromJson( Map json, { T Function(dynamic)? fromJsonT, }) { if (fromJsonT == null) { return ResponseData( status: json['status'], errorCode: json['errorCode'], errorCodeName: json['errorCodeName'], errorMsg: json['errorMsg'], body: json['body'], time: json['time'], ); } else { return ResponseData( status: json['status'], errorCode: json['errorCode'], errorCodeName: json['errorCodeName'], errorMsg: json['errorMsg'], body: json['body'] != null ? _parseData(json['body'], fromJsonT) : null, time: json['time'], ); } } } /// 超时拦截器 class TimeOutInterceptor extends Interceptor { static const int globalTimeoutSeconds = 15; final Map _timers = {}; @override void onError(DioException err, ErrorInterceptorHandler handler) async { if (err.type == DioExceptionType.connectionTimeout || err.type == DioExceptionType.receiveTimeout || err.type == DioExceptionType.sendTimeout) { print('超时错误: URL => ${err.requestOptions.baseUrl}'); print('当前使用的Host: ${ATGlobalConfig.apiHost}'); } // 请求出错,取消计时器 final String requestKey = err.requestOptions.uri.toString(); _timers[requestKey]?.cancel(); _timers.remove(requestKey); handler.next(err); } @override void onRequest(RequestOptions options, RequestInterceptorHandler handler) { // 为每个请求创建超时计时器 final cancelToken = options.cancelToken ?? CancelToken(); final String requestKey = options.uri.toString(); // 设置15秒后自动取消 _timers[requestKey] = Timer( const Duration(seconds: globalTimeoutSeconds), () { ATLoadingManager.veilRoutine(); if (!cancelToken.isCancelled) { cancelToken.cancel('请求超时(${globalTimeoutSeconds}秒)'); // 从映射中移除计时器 _timers.remove(requestKey); } } ); handler.next(options); } @override void onResponse(Response response, ResponseInterceptorHandler handler) { // 请求成功完成,取消计时器 final String requestKey = response.requestOptions.uri.toString(); _timers[requestKey]?.cancel(); _timers.remove(requestKey); handler.next(response); } }