import 'dart:convert'; import 'dart:io' show Platform; import 'package:dio/dio.dart'; // import 'package:flutter_easyloading/flutter_easyloading.dart'; // 已替换为自定义组件 import 'package:flutter_loggy_dio/flutter_loggy_dio.dart'; import 'package:kaer_with_panels/app/common/app_config.dart'; import 'package:kaer_with_panels/app/common/app_run_data.dart'; import 'package:kaer_with_panels/app/network/base_response.dart'; import 'package:kaer_with_panels/app/localization/kr_language_utils.dart'; import 'package:kaer_with_panels/app/utils/kr_common_util.dart'; import 'package:kaer_with_panels/app/services/kr_site_config_service.dart'; // import 'package:crypto/crypto.dart'; // import 'package:encrypt/encrypt.dart'; import 'package:loggy/loggy.dart'; import '../utils/kr_aes_util.dart'; import '../utils/kr_log_util.dart'; // import 'package:video/app/utils/common_util.dart'; // import 'package:video/app/utils/log_util.dart'; /// 定义请求方法的枚举 enum HttpMethod { GET, POST, DELETE, PUT } /// 封装请求 class HttpUtil { final Dio _dio = Dio(); static final HttpUtil _instance = HttpUtil._internal(); HttpUtil._internal() { initDio(); } factory HttpUtil() => _instance; static HttpUtil getInstance() { return _instance; } /// 对dio进行配置 void initDio() { // 不使用 Loggy,改用自定义简洁拦截器 _dio.interceptors.add(_KRSimpleHttpInterceptor()); _dio.options.baseUrl = AppConfig.getInstance().baseUrl; // 设置连接超时时间 _dio.options.connectTimeout = const Duration(seconds: 60); _dio.options.receiveTimeout = const Duration(seconds: 60); _dio.options.sendTimeout = const Duration(seconds: 60); // 设置请求头 _dio.options.headers = { 'Accept': 'application/json', 'Content-Type': 'application/json; charset=UTF-8', // 移除固定的UserAgent,使用动态的 }; // 设置响应类型 _dio.options.responseType = ResponseType.json; // 设置验证状态 _dio.options.validateStatus = (status) { return status != null && status >= 200 && status < 500; }; } /// 更新baseUrl void updateBaseUrl() { String newBaseUrl = AppConfig.getInstance().baseUrl; if (_dio.options.baseUrl != newBaseUrl) { KRLogUtil.kr_i('🔄 更新baseUrl: ${_dio.options.baseUrl} -> $newBaseUrl', tag: 'HttpUtil'); _dio.options.baseUrl = newBaseUrl; } } /// 初始化请求头 :signature签名字符串 Map _initHeader( String signature, String? userId, String? token) { Map map = {}; if (KRAppRunData().kr_isLogin.value == true) { map["Authorization"] = KRAppRunData().kr_token; } // 添加语言请求头 map["lang"] = KRLanguageUtils.getCurrentLanguageCode(); // 添加动态UserAgent头 map["User-Agent"] = _kr_getUserAgent(); return map; } /// 获取当前系统的 user_agent String _kr_getUserAgent() { if (Platform.isAndroid) { return 'android'; } else if (Platform.isIOS) { return 'ios'; } else if (Platform.isMacOS) { return 'mac'; } else if (Platform.isWindows) { return 'windows'; } else if (Platform.isLinux) { return 'linux'; } else if (Platform.isFuchsia) { return 'harmony'; } else { return 'unknown'; } } /// request请求:T为转换的实体类, path:请求地址,query:请求参数, method: 请求方法, isShowLoading(可选): 是否显示加载中的状态,默认true显示, false为不显示 Future> request(String path, Map params, {HttpMethod method = HttpMethod.POST, bool isShowLoading = true}) async { try { // 每次请求前更新baseUrl,确保使用最新的域名 updateBaseUrl(); if (isShowLoading) { KRCommonUtil.kr_showLoading(); } var map = {}; // 判断是否需要加密:根据站点配置的 enable_security 字段 final shouldEncrypt = KRSiteConfigService().isDeviceSecurityEnabled(); if (shouldEncrypt && path.contains("app")) { KRLogUtil.kr_i('🔐 需要加密请求数据', tag: 'HttpUtil'); final plainText = jsonEncode(params); map = KRAesUtil.encryptData(plainText, AppConfig.kr_encryptionKey); } else { map = params; } // 初始化请求头 final headers = _initHeader('signature', 'userId', 'token'); // 调试:打印请求头 KRLogUtil.kr_i('🔍 请求头: $headers', tag: 'HttpUtil'); Response> responseTemp; if (method == HttpMethod.GET) { responseTemp = await _dio.get>( path, queryParameters: map, options: Options( contentType: "application/json", headers: headers, // 添加请求头 ), ); } else if (method == HttpMethod.DELETE) { responseTemp = await _dio.delete>( path, data: map, options: Options( contentType: "application/json", headers: headers, // 添加请求头 ), ); } else if (method == HttpMethod.PUT) { responseTemp = await _dio.put>( path, data: map, options: Options( contentType: "application/json", headers: headers, // 添加请求头 ), ); } else { responseTemp = await _dio.post>( path, data: map, options: Options( contentType: "application/json", headers: headers, // 添加请求头 ), ); } if (isShowLoading) { KRCommonUtil.kr_hideLoading(); } return BaseResponse.fromJson(responseTemp.data!); } on DioException catch (err) { if (isShowLoading) { KRCommonUtil.kr_hideLoading(); } int code = -90000; String msg = ""; msg = err.message ?? err.type.toString(); switch (err.type) { case DioExceptionType.connectionTimeout: code = -90001; break; case DioExceptionType.sendTimeout: code = -90002; break; case DioExceptionType.receiveTimeout: code = -90003; break; case DioExceptionType.badResponse: code = err.response?.statusCode ?? -90004; break; case DioExceptionType.cancel: break; case DioExceptionType.connectionError: code = -90006; break; case DioExceptionType.badCertificate: code = -90007; break; default: if (err.error != null) { if (err.error.toString().contains("Connection reset by peer")) { code = -90008; } } } return BaseResponse.fromJson({ 'code': code, 'msg': msg, 'data': {} }); } catch (e) { if (isShowLoading) { KRCommonUtil.kr_hideLoading(); } return BaseResponse.fromJson({ 'code': -90000, 'msg': e.toString(), 'data': {} }); } } } /// 拦截器(简洁格式,无边框) class MyInterceptor extends Interceptor { @override void onRequest(RequestOptions options, RequestInterceptorHandler handler) { print('>>> Request │ ${options.method} │ ${options.uri}'); if (options.data != null) { print('Body: ${options.data}'); } handler.next(options); } @override void onResponse(Response response, ResponseInterceptorHandler handler) { print('<<< Response │ ${response.requestOptions.method} │ ${response.statusCode} ${response.statusMessage} │ ${response.requestOptions.uri}'); if (response.data != null) { print('Body: ${response.data}'); } handler.next(response); } @override void onError(DioException err, ErrorInterceptorHandler handler) { print('<<< Error │ ${err.requestOptions.method} │ ${err.requestOptions.uri}'); print('Error Type: ${err.type}'); if (err.message != null) { print('Error Message: ${err.message}'); } if (err.response?.data != null) { print('Response Data: ${err.response?.data}'); } handler.next(err); } } /// 自定义简洁 HTTP 拦截器(无边框符号) class _KRSimpleHttpInterceptor extends Interceptor { @override void onRequest(RequestOptions options, RequestInterceptorHandler handler) { print('>>> Request │ ${options.method} │ ${options.uri}'); if (options.data != null) { print('Body: ${options.data}'); } handler.next(options); } @override void onResponse(Response response, ResponseInterceptorHandler handler) { print('<<< Response │ ${response.requestOptions.method} │ ${response.statusCode} ${response.statusMessage} │ ${response.requestOptions.uri}'); if (response.data != null) { print('Body: ${response.data}'); } handler.next(response); } @override void onError(DioException err, ErrorInterceptorHandler handler) { print('<<< Error │ ${err.requestOptions.method} │ ${err.requestOptions.uri}'); print('Error Type: ${err.type}'); if (err.message != null) { print('Error Message: ${err.message}'); } if (err.response?.data != null) { print('Response Data: ${err.response?.data}'); } handler.next(err); } }