hi-client/lib/app/network/http_util.dart

311 lines
9.4 KiB
Dart
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<String, dynamic> _initHeader(
String signature, String? userId, String? token) {
Map<String, dynamic> map = <String, dynamic>{};
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<BaseResponse<T>> request<T>(String path, Map<String, dynamic> params,
{HttpMethod method = HttpMethod.POST, bool isShowLoading = true}) async {
try {
// 每次请求前更新baseUrl确保使用最新的域名
updateBaseUrl();
if (isShowLoading) {
KRCommonUtil.kr_showLoading();
}
var map = <String, dynamic>{};
// 判断是否需要加密:根据站点配置的 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<Map<String, dynamic>> responseTemp;
if (method == HttpMethod.GET) {
responseTemp = await _dio.get<Map<String, dynamic>>(
path,
queryParameters: map,
options: Options(
contentType: "application/json",
headers: headers, // 添加请求头
),
);
} else if (method == HttpMethod.DELETE) {
responseTemp = await _dio.delete<Map<String, dynamic>>(
path,
data: map,
options: Options(
contentType: "application/json",
headers: headers, // 添加请求头
),
);
} else if (method == HttpMethod.PUT) {
responseTemp = await _dio.put<Map<String, dynamic>>(
path,
data: map,
options: Options(
contentType: "application/json",
headers: headers, // 添加请求头
),
);
} else {
responseTemp = await _dio.post<Map<String, dynamic>>(
path,
data: map,
options: Options(
contentType: "application/json",
headers: headers, // 添加请求头
),
);
}
if (isShowLoading) {
KRCommonUtil.kr_hideLoading();
}
return BaseResponse<T>.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<T>.fromJson({
'code': code,
'msg': msg,
'data': <String, dynamic>{}
});
} catch (e) {
if (isShowLoading) {
KRCommonUtil.kr_hideLoading();
}
return BaseResponse<T>.fromJson({
'code': -90000,
'msg': e.toString(),
'data': <String, dynamic>{}
});
}
}
}
/// 拦截器(简洁格式,无边框)
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);
}
}