Marking.Client.Moblie/marking_app/lib/utils/request/rest_dio.dart

402 lines
13 KiB
Dart
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:io';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:dio/dio.dart';
import 'package:dio/adapter.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:marking_app/common/config/request_config.dart';
import 'package:marking_app/routes/RouterManager.dart';
import 'package:marking_app/utils/index.dart';
import 'package:marking_app/utils/the_global.dart';
import 'package:package_info/package_info.dart';
class RestDio {
late Dio _dio;
// 单例模式
static final RestDio _instance = RestDio._internal();
factory RestDio() => _instance;
RestDio._internal() {
init();
}
// 初始化请求配置
init() {
BaseOptions options = BaseOptions(
connectTimeout: RequestConfig.connectTimeout,
receiveTimeout: RequestConfig.receiveTimeout,
);
_dio = Dio(options);
_dio.interceptors.add(AuthInterceptor()); // 添加 token
_dio.interceptors.add(ResponseHandle()); // 添加 数据返回拦截
_dio.interceptors.add(TheError()); // 添加 数据返回拦截
const isProd = bool.fromEnvironment('dart.vm.product');
if (!isProd && RequestConfig.requestDataPrinting) {
_dio.interceptors.add(LogInterceptor(responseBody: true, requestBody: true)); //添加日志
}
// 添加https证书
setHttpsPEM();
// setHttpsPKCS12();
// 使用代理
// setFindProxy();
}
String PEM = "XXXXX"; // certificate content
String PKCS12File = "XXXXX"; // certificate content
//dio 基本方法
Future<Dio> getDio() async {
return _dio;
}
//添加证书
setHttpsPEM() async {
(_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client) {
client.badCertificateCallback = (X509Certificate cert, String host, int port) {
// if (cert.pem == PEM) {
// // Verify the certificate
// return true;
// }
// return false;
return true;
};
};
}
setHttpsPKCS12() async {
(_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client) {
SecurityContext sc = new SecurityContext();
//file is the path of certificate
sc.setTrustedCertificates(PKCS12File);
HttpClient httpClient = new HttpClient(context: sc);
return httpClient;
};
}
//设置代理
setFindProxy() async {
// 设置请求拦截器
_dio.interceptors.add(InterceptorsWrapper(onRequest: (options, handler) {
// 判断 URI 的路径是否包含指定字符串
if (options.uri.path.contains(RequestConfig.hwProxyKeywords)) {
// 设置代理地址
_dio.httpClientAdapter = DefaultHttpClientAdapter();
(_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client) {
client.findProxy = (uri) {
print('进入开始代理...............');
return RequestConfig.proBaseUrlOfHomework;
};
};
}
return handler.next(options); // 继续发送请求
}));
}
}
/*
*
*AuthInterceptor
*添加header认证
* */
class AuthInterceptor extends Interceptor {
String PLATFORM = "android"; //可根据代码进行判断
@override
onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
//获取app版本
PackageInfo packageInfo = await PackageInfo.fromPlatform();
String version = packageInfo.version;
if (Platform.isIOS) {
PLATFORM = "ios";
} else if (Platform.isAndroid) {
PLATFORM = "android";
} else if (Platform.isWindows) {
PLATFORM = "Windows";
} else if (Platform.isMacOS) {
PLATFORM = "macos";
} else if (Platform.isLinux) {
PLATFORM = "Linux";
}
Map<String, String> headers = {};
headers["Accept-Charset"] = "utf-8";
headers["Connection"] = "keep-alive";
headers["Accept"] = "*/*";
headers["x-version"] = version; //自己更改配置
headers["x-platform"] = PLATFORM;
//获取存储数据 保存header token
String? token = await FastData.getInstance().getToken();
if (null != token && token.isNotEmpty) {
headers["Authorization"] = 'Bearer $token'; //添加自己项目中的请求头 进行保存
}
options.headers = headers;
Uri uri = options.uri;
print(uri.toString());
// 判断请求的 URL 是否包含指定字符串
if (uri.toString().contains(RequestConfig.hwProxyKeywords)) {
String newPath = options.path.replaceFirst(RegExp('^${RequestConfig.hwProxyKeywords}'), '');
options.path = newPath;
// 修改请求的 URL
options.baseUrl = RequestConfig.proBaseUrlOfHomework;
}
// print('请求参数query' + jsonEncode(options.queryParameters));
// print('请求参数data' + jsonEncode(options.data));
return super.onRequest(options, handler);
}
}
/*
* ResponseHandle
* 监听返回响应
**/
class ResponseHandle extends Interceptor {
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
const isProd = bool.fromEnvironment('dart.vm.product');
if (!isProd && RequestConfig.requestDataPrinting) {
printJson(response.data);
}
super.onResponse(response, handler);
}
}
/*
* ResponseHandle
* 监听返回响应
**/
class TheError extends Interceptor {
// 是否有网
Future<bool> isConnected() async {
var connectivityResult = await (Connectivity().checkConnectivity());
return connectivityResult != ConnectivityResult.none;
}
@override
Future<void> onError(DioError err, ErrorInterceptorHandler handler) async {
// 自定义一个socket实例因为dio原生的实例message属于是只读的
// 这里是我单独加的因为默认的dio err实例的几种类型缺少无网络情况下的错误提示信息
if (err.error is SocketException) {
err.error = MyDioSocketException(
err.message.contains('111') ? "服务器拒绝连接,请重试" : err.message,
osError: err.error?.osError,
address: err.error?.address,
port: err.error?.port,
);
}
// dio默认的错误实例如果是没有网络只能得到一个未知错误无法精准的得知是否是无网络的情况
if (err.type == DioErrorType.other) {
bool isConnectNetWork = await isConnected();
if (!isConnectNetWork && err.error is MyDioSocketException) {
err.error.message = "当前网络不可用,请检查您的网络";
}
}
// error统一处理
AppException appException = AppException.create(err);
// 错误提示
// debugPrint('DioError===: ${appException.toString()}');
err = appException;
return super.onError(err, handler);
}
}
String getDioErrorTypeStr(DioError err) {
DioErrorType errorType = err.type;
String str;
switch (errorType) {
case DioErrorType.connectTimeout:
str = '连接超时,请检查网络再重试';
break;
case DioErrorType.sendTimeout:
str = '发送时间超时,请重试';
break;
case DioErrorType.receiveTimeout:
str = '接收数据超时,请重试';
break;
case DioErrorType.response:
str = '请求返回失败';
break;
case DioErrorType.cancel:
str = '请求取消';
break;
case DioErrorType.other:
str = '请求其他错误';
break;
}
return str;
}
/// 自定义异常
class AppException extends DioError {
final String _message;
final int _code;
AppException(this._code, this._message, StackTrace? theStackTrace,
{required super.requestOptions, super.type, super.error}) {
super.stackTrace = theStackTrace;
}
@override
String toString() {
return "$_code$_message" + super.toString();
}
String getMessage() {
return _message;
}
factory AppException.create(DioError error) {
switch (error.type) {
case DioErrorType.cancel:
{
return AppException(-1, "请求取消", error.stackTrace,
requestOptions: error.requestOptions, type: error.type, error: error.error);
}
case DioErrorType.connectTimeout:
{
return AppException(-1, "连接超时", error.stackTrace,
requestOptions: error.requestOptions, type: error.type, error: error.error);
}
case DioErrorType.sendTimeout:
{
return AppException(-1, "请求超时", error.stackTrace,
requestOptions: error.requestOptions, type: error.type, error: error.error);
}
case DioErrorType.receiveTimeout:
{
return AppException(-1, "响应超时", error.stackTrace,
requestOptions: error.requestOptions, type: error.type, error: error.error);
}
case DioErrorType.response:
{
try {
int? errCode = error.response!.statusCode;
// String errMsg = error.response.statusMessage;
// return ErrorEntity(code: errCode, message: errMsg);
switch (errCode) {
case 400:
{
return AppException(errCode!, "请求语法错误", error.stackTrace,
requestOptions: error.requestOptions, type: error.type, error: error.error);
}
case 401:
{
var currentContext = TheGlobal.navigatorKey.currentState?.overlay?.context;
if (currentContext != null) {
var routePath = ModalRoute.of(currentContext)?.settings;
if (routePath != null) {
} else {
if (TheGlobal.navigatorKey.currentContext != null) {
ExceptionHandle.toLogin(TheGlobal.navigatorKey.currentContext);
}
}
}
return AppException(errCode!, "登录信息过期,请重新登录", error.stackTrace,
requestOptions: error.requestOptions, type: error.type, error: error.error);
}
case 403:
{
return AppException(errCode!, "服务器拒绝执行", error.stackTrace,
requestOptions: error.requestOptions, type: error.type, error: error.error);
}
case 404:
{
return AppException(errCode!, "无法连接服务器", error.stackTrace,
requestOptions: error.requestOptions, type: error.type, error: error.error);
}
case 405:
{
return AppException(errCode!, "请求方法被禁止", error.stackTrace,
requestOptions: error.requestOptions, type: error.type, error: error.error);
}
case 500:
{
return AppException(errCode!, "服务器内部错误", error.stackTrace,
requestOptions: error.requestOptions, type: error.type, error: error.error);
}
case 502:
{
return AppException(errCode!, "无效的请求", error.stackTrace,
requestOptions: error.requestOptions, type: error.type, error: error.error);
}
case 503:
{
return AppException(errCode!, "服务器挂了", error.stackTrace,
requestOptions: error.requestOptions, type: error.type, error: error.error);
}
case 505:
{
return AppException(errCode!, "不支持HTTP协议请求", error.stackTrace,
requestOptions: error.requestOptions, type: error.type, error: error.error);
}
default:
{
// return ErrorEntity(code: errCode, message: "未知错误");
return AppException(errCode!, error.response!.statusMessage!, error.stackTrace,
requestOptions: error.requestOptions, type: error.type, error: error.error);
}
}
} on Exception catch (_) {
return AppException(-1, "未知错误", error.stackTrace,
requestOptions: error.requestOptions, type: error.type, error: error.error);
}
}
default:
{
return AppException(-1, error.error.message, error.stackTrace,
requestOptions: error.requestOptions, type: error.type, error: error.error);
}
}
}
}
class ExceptionHandle {
// 异常处理信息
static void exceptionPrompt(BuildContext context, AppException err, {bool logicHandle = true}) {
ToastUtils.getFluttertoast(
context: context,
msg: err._message,
backgroundColor: Colors.grey[350],
toastLength: Toast.LENGTH_LONG,
);
if (!logicHandle) return;
switch (err._code) {
case 401:
toLogin(context); // 重新前往登录
break;
default:
}
}
static void toLogin(context, {int timeer = 800}) {
setTimeOut(
timeer,
() => RouterManager.router.navigateTo(context, RouterManager.loginPath, clearStack: true),
);
}
}
// 这里是一个我单独写得soket错误实例因为dio默认生成的是不允许修改message内容的我只能自定义一个使用
class MyDioSocketException extends SocketException {
String message;
MyDioSocketException(
this.message, {
osError,
address,
port,
}) : super(
message,
osError: osError,
address: address,
port: port,
);
}