base_dio.dart 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. import 'dart:convert';
  2. import 'package:connectivity_plus/connectivity_plus.dart';
  3. import 'package:dio/dio.dart';
  4. import 'package:lszlgl/base/base_lifecycle_state.dart';
  5. import 'package:lszlgl/main.dart';
  6. import 'package:lszlgl/service/user_service.dart';
  7. class BaseDio {
  8. static BaseDio? _instance;
  9. static BaseDio get() => _instance ??= BaseDio._();
  10. BaseDio._() {
  11. BaseOptions options = BaseOptions();
  12. dio = Dio(options);
  13. // 添加request拦截器
  14. dio.interceptors.add(MyInterceptor());
  15. // // 添加error拦截器
  16. // dio.interceptors.add(ErrorInterceptor());
  17. // // // 添加cache拦截器
  18. // dio.interceptors.add(NetCacheInterceptor());
  19. // // // 添加retry拦截器
  20. // dio.interceptors.add(
  21. // RetryOnConnectionChangeInterceptor(
  22. // requestRetrier: DioConnectivityRequestRetrier(
  23. // dio: dio,
  24. // connectivity: Connectivity(),
  25. // ),
  26. // ),
  27. // );
  28. }
  29. late final Dio dio;
  30. /// 初始化公共属性
  31. /// * [baseUrl] 前缀地址
  32. /// * [receiveTimeout] 接收超出时间
  33. /// * [connectTimeout] 连接超时时间
  34. /// * [sendTimeout] 发送超时时间
  35. void init({
  36. String? baseUrl,
  37. Duration? receiveTimeout = const Duration(seconds: 60),
  38. Duration? connectTimeout = const Duration(seconds: 30),
  39. Duration? sendTimeout = const Duration(seconds: 60),
  40. Map<String, String>? headers,
  41. List<Interceptor>? interceptors,
  42. }) {
  43. dio.options.copyWith(
  44. baseUrl: baseUrl,
  45. connectTimeout: connectTimeout,
  46. receiveTimeout: receiveTimeout,
  47. sendTimeout: sendTimeout,
  48. headers: headers,
  49. );
  50. if (interceptors != null && interceptors.isNotEmpty) {
  51. dio.interceptors.addAll(interceptors);
  52. }
  53. }
  54. }
  55. /// 拦截器
  56. class MyInterceptor extends Interceptor {
  57. @override
  58. void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
  59. // 请求
  60. var login = UserService.get().getLogin();
  61. if (login != null) {
  62. // 已登录添加token
  63. options.headers['Authorization'] = 'Bearer ${login.accessToken}';
  64. }
  65. Map<String, Object?> map = {};
  66. map['url'] = options.uri;
  67. map['method'] = options.method;
  68. map['headers'] = options.headers;
  69. if (options.data is List || options.data is Map) {
  70. map['data'] = jsonEncode(options.data);
  71. } else {
  72. map['data'] = options.data.toString();
  73. }
  74. if (options.queryParameters.isNotEmpty) map['queryParameters'] = options.queryParameters;
  75. if (options.extra.isNotEmpty) map['extra'] = options.extra;
  76. logger.i('ApiRequest: $map');
  77. handler.next(options);
  78. }
  79. @override
  80. void onResponse(Response response, ResponseInterceptorHandler handler) {
  81. // 响应
  82. Map<String, Object?> map = {};
  83. map['url'] = response.requestOptions.uri;
  84. map['statusCode'] = response.statusCode;
  85. map['statusMessage'] = response.statusMessage;
  86. if (response.data != null) {
  87. var code = response.data!['code'];
  88. var msg = response.data!['msg'];
  89. map['code'] = code;
  90. map['msg'] = msg;
  91. map['data'] = jsonEncode(response.data!['data']);
  92. if (code != 0) {
  93. return handler.reject(
  94. DioException(
  95. requestOptions: response.requestOptions,
  96. response: response,
  97. type: DioExceptionType.badResponse,
  98. message: msg,
  99. ),
  100. true,
  101. );
  102. }
  103. }
  104. if (response.extra.isNotEmpty) map['extra'] = response.extra;
  105. logger.i('ApiResponse: $map');
  106. handler.next(response);
  107. }
  108. // 是否有网
  109. Future<bool> isConnected() async {
  110. var connectivityResult = await (Connectivity().checkConnectivity());
  111. return connectivityResult != ConnectivityResult.none;
  112. }
  113. @override
  114. void onError(DioException err, ErrorInterceptorHandler handler) async {
  115. if (err.type == DioExceptionType.badResponse) {
  116. logger.e('ApiErrorResponse: ${err.response}');
  117. } else {
  118. logger.e('ApiErrorSource: $err');
  119. }
  120. // 增加网络检测
  121. if (err.type == DioExceptionType.unknown) {
  122. bool isConnectNetWork = await isConnected();
  123. if (!isConnectNetWork) {
  124. err.copyWith(message: '当前网络不可用,请检查您的网络');
  125. }
  126. }
  127. // error统一处理
  128. AppException appException = AppException.create(err);
  129. err.copyWith(error: appException);
  130. // 响应
  131. Map<String, Object?> map = {};
  132. map['url'] = err.requestOptions.uri;
  133. map['errorType'] = err.type;
  134. map['statusCode'] = err.response?.statusCode;
  135. map['msg'] = appException.message;
  136. if (err.response?.extra.isNotEmpty ?? false) map['extra'] = err.response?.extra;
  137. logger.e('ApiError: $map');
  138. MyNavigator.showToast(appException.message ?? '');
  139. handler.next(err);
  140. }
  141. }
  142. /// 自定义异常
  143. class AppException implements Exception {
  144. final String? message;
  145. final int code;
  146. AppException(
  147. this.code,
  148. this.message,
  149. );
  150. @override
  151. String toString() {
  152. return 'code:$code, message:$message';
  153. }
  154. factory AppException.create(DioException error) {
  155. switch (error.type) {
  156. case DioExceptionType.connectionTimeout:
  157. return AppException(-1, '连接超时');
  158. case DioExceptionType.sendTimeout:
  159. return AppException(-1, '请求超时');
  160. case DioExceptionType.receiveTimeout:
  161. return AppException(-1, '响应超时');
  162. case DioExceptionType.badCertificate:
  163. return AppException(-1, '证书错误');
  164. case DioExceptionType.badResponse:
  165. if (error.response?.data is Map) {
  166. var code = error.response?.data['code'] ?? -1;
  167. if (code == 401) UserService.get().logout();
  168. return AppException(code, error.response?.data['msg'] ?? '');
  169. }
  170. return AppException(-1, '请求失败');
  171. case DioExceptionType.cancel:
  172. return AppException(-1, "请求取消");
  173. case DioExceptionType.connectionError:
  174. return AppException(-1, '连接超时');
  175. case DioExceptionType.unknown:
  176. return AppException(-1, error.message);
  177. }
  178. }
  179. }