Files
flutter_common/flutter_common/lib/http/http_utils.dart
2025-10-20 10:44:59 +08:00

327 lines
8.9 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:developer';
import 'dart:ui';
import 'package:dio/dio.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import '../utils/toast_utils.dart';
///请求方式-枚举类型
enum MethodType { get, post, delete, put, patch }
class HttpUtils {
static final HttpUtils _instance = HttpUtils._internal(baseUrl: '');
factory HttpUtils() => _instance;
late Dio dio;
HttpUtils._internal({required String baseUrl}) {
BaseOptions options = BaseOptions(
baseUrl: baseUrl,
contentType: 'application/json; charset=utf-8',
connectTimeout: const Duration(milliseconds: 15000),
receiveTimeout: const Duration(milliseconds: 15000),
responseType: ResponseType.json,
validateStatus: (status) {
return true;
},
);
dio = Dio(options);
/// 添加请求日志
dio.interceptors.add(LogInterceptor(
requestBody: true,
responseHeader: false,
responseBody: false,
error: false,
));
/// 添加拦截器
dio.interceptors.add(InterceptorsWrapper(
onResponse: (response, handler) {
/// 打印返回值
const bool inProduction = bool.fromEnvironment("dart.vm.product");
if (!inProduction) {
log(
jsonEncode(response.data),
name: 'Response Text: ',
);
}
/// 对接口抛出异常的检查
_apiVerify(response);
return handler.next(response);
},
));
}
///统一请求入口
static Future<NetResult> request(
String baseUrl,
String path, {
String? token,
MethodType method = MethodType.get,
Map<String, String>? headers,
Map<String, dynamic>? body,
Map<String, dynamic>? queryParameters,
bool isShowLoading = false,
CancelToken? cancelToken,
VoidCallback? unLoginAction,
}) async {
///开始网络请求
late NetResult netResult;
Dio dio = HttpUtils._internal(baseUrl: baseUrl).dio;
// String? token1 = token ?? '';
Map<String, dynamic> headerMap = {};
if (headers != null) headerMap.addAll(headers);
headerMap['token'] = token;
headerMap['Authorization'] = token;
Options options = Options(
method: method.name,
headers: headerMap,
);
CancelToken newCancelToken = cancelToken ?? CancelToken();
try {
if (isShowLoading) {
await EasyLoading.show(
// status: 'loading...',
maskType: EasyLoadingMaskType.black,
);
}
final response = await dio.request(
path,
options: options,
queryParameters: queryParameters,
data: body,
cancelToken: newCancelToken,
);
// if (response.headers["authorization"] != null) {
// LocalStore.setValue(
// key: StoreValue.tokenKey,
// value: response.headers["authorization"]![0]);
// }
if (isShowLoading) EasyLoading.dismiss();
netResult = NetResult(
headers: response.headers,
result: response.data,
statusCode: response.statusCode ?? 0,
error: _apiIsSucceed(response),
);
} on DioError catch (error) {
if (isShowLoading) EasyLoading.dismiss();
_formatError(error);
netResult = NetResult(
errorMeg: error.message ?? '服务器出现错误',
);
}
return netResult;
}
///下载
static Future<NetResult> download(
String path,
String savePath, {
ProgressCallback? onReceiveProgress,
Map<String, dynamic>? queryParameters,
CancelToken? cancelToken,
bool deleteOnError = true,
String lengthHeader = Headers.contentLengthHeader,
data,
Options? options,
}) async {
///开始网络请求
late NetResult netResult;
try {
Response response = await Dio().download(
path,
savePath,
onReceiveProgress: onReceiveProgress,
queryParameters: queryParameters,
cancelToken: cancelToken,
deleteOnError: deleteOnError,
lengthHeader: lengthHeader,
data: data,
options: options,
);
netResult = NetResult(
headers: response.headers,
result: 'Download successful',
statusCode: response.statusCode ?? 0,
error: response.statusCode != 200,
);
} on DioError catch (error) {
_formatError(error);
netResult = NetResult(
errorMeg: error.message ?? '服务器出现错误',
result: 'Download failure',
);
}
return netResult;
}
///判断接口是否成功
static bool _apiIsSucceed(Response response) {
if (response.data != null && response.data != '') {
Map<String, dynamic> map = response.data;
return map['resultCode'] == 'OK' ? false : true;
}
return false;
}
///接口校验
static void _apiVerify(Response response, {VoidCallback? unLoginAction}) {
if (response.data != null && response.data != '') {
///判断返回值是否是Map
if (response.data is Map) {
Map<String, dynamic> map = response.data;
String resultCode = map['resultCode'];
if (resultCode.toUpperCase() == "FAIL") {
throw DioException(
requestOptions: RequestOptions(path: ''),
response: response,
type: DioExceptionType.unknown,
error: response.data,
message: map['resultMsg'],
);
}
if (resultCode.toUpperCase() == "UNLOGIN") {
unLoginAction?.call();
return;
}
} else if (response.data is String) {
throw DioException(
requestOptions: RequestOptions(path: ''),
response: response,
type: DioExceptionType.unknown,
error: response.data,
message: response.data,
);
}
} else {
throw DioException(
requestOptions: RequestOptions(path: ''),
response: response,
type: DioExceptionType.unknown,
error: response.data,
message: response.data,
);
}
}
/*
* Dio库error统一处理
*/
static void _formatError(DioException error) {
switch (error.type) {
case DioExceptionType.cancel:
break;
case DioExceptionType.connectionTimeout:
ToastUtils.showToast(msg: '网络连接超时');
break;
case DioExceptionType.sendTimeout:
ToastUtils.showToast(msg: '网络请求超时');
break;
case DioExceptionType.receiveTimeout:
ToastUtils.showToast(msg: '服务响应超时');
break;
case DioExceptionType.unknown:
ToastUtils.showToast(msg: error.message);
break;
case DioExceptionType.badResponse:
try {
int? errCode = error.response!.statusCode;
String? errMsg = error.response!.statusMessage;
switch (errCode) {
case 400:
ToastUtils.errorToast(errorText: '请求语法错误');
break;
case 401:
ToastUtils.errorToast(errorText: '没有权限');
break;
case 403:
ToastUtils.errorToast(errorText: '服务器拒绝执行');
break;
case 404:
ToastUtils.errorToast(errorText: '无法连接服务器');
break;
case 405:
ToastUtils.errorToast(errorText: '请求方法被禁止');
break;
case 500:
ToastUtils.errorToast(errorText: '服务器出现问题');
break;
case 502:
ToastUtils.errorToast(errorText: '无效的请求');
break;
case 503:
ToastUtils.errorToast(errorText: '服务器挂了');
break;
case 505:
ToastUtils.errorToast(errorText: '不支持HTTP协议请求');
break;
default:
ToastUtils.errorToast(errorText: errMsg ?? '未知错误');
break;
}
} on Exception catch (_) {
ToastUtils.errorToast(errorText: '未知错误');
break;
}
break;
default:
ToastUtils.errorToast(errorText: error.message);
break;
}
}
}
/// 自定义Dio返回类
class NetResult {
dynamic result;
dynamic headers;
int total;
bool error;
int statusCode;
String errorMeg;
bool get success => !error;
NetResult({
this.result,
this.headers,
this.statusCode = -1,
this.error = true,
this.total = 0,
this.errorMeg = '',
});
@override
String toString() {
return 'NetResultstatusCode: $statusCode \n'
'NetResult: headers: $headers \n'
'NetResult: error: $error \n'
'NetResult: total: $total \n'
'NetResult: errorMeg: $errorMeg \n'
'NetResult: result: ${result.toString()}';
}
}
/// 自定义Dio取消请求处理类
class CustomCancelToken {
static CancelToken cancelToken = CancelToken();
static cancel() {
cancelToken.cancel('取消请求');
cancelToken = CancelToken();
}
}