dio_client.dart 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. import 'dart:convert';
  2. import 'dart:io';
  3. import 'package:connectivity_plus/connectivity_plus.dart';
  4. import 'package:dio/dio.dart';
  5. import 'package:flutter/cupertino.dart';
  6. import 'package:logger/logger.dart';
  7. import '../common/SharedPreferencesUtil.dart';
  8. //import 'custom_interceptors.dart';
  9. class DioClient {
  10. static final DioClient _instance = DioClient._internal();
  11. late Dio _dio;
  12. factory DioClient() => _instance;
  13. final Logger _logger = Logger();
  14. DioClient._internal() {
  15. _dio = Dio(BaseOptions(
  16. baseUrl: 'https://api.androidrj01.top', // 你的API地址
  17. connectTimeout: 5000,
  18. receiveTimeout: 3000,
  19. ));
  20. // 仅在调试模式下添加日志拦截器
  21. assert(() {
  22. _dio.interceptors.add(LogInterceptor(
  23. request: true,
  24. requestBody: true,
  25. responseBody: true,
  26. error: true,
  27. logPrint: _logger.d, // 使用 Logger 插件打印日志
  28. ));
  29. return true;
  30. }());
  31. final customInterceptor = CustomInterceptors(_dio);
  32. //token
  33. _dio.interceptors.add(TokenInterceptor());
  34. // 添加拦截器
  35. _dio.interceptors.add(customInterceptor);
  36. // 添加响应拦截器
  37. _dio.interceptors.add(InterceptorsWrapper(
  38. onResponse: (Response<dynamic> response, ResponseInterceptorHandler handler) {
  39. final responseData = response.data as Map<String, dynamic>;
  40. if (responseData['ret'] == 1) {
  41. customInterceptor.resetRetryCount(); // 当请求成功时重置重试计数器
  42. handler.next(
  43. Response<dynamic>(
  44. data: responseData['data'],
  45. headers: response.headers,
  46. requestOptions: response.requestOptions,
  47. statusCode: response.statusCode,
  48. ),
  49. );
  50. } else {
  51. handler.reject(
  52. DioError(
  53. requestOptions: response.requestOptions,
  54. error: AppException(message: responseData['msg'] ?? 'Unknown Error',statusCode: responseData['ret'] ?? -1),
  55. ),
  56. );
  57. }
  58. },
  59. ));
  60. }
  61. Dio get dio => _dio;
  62. }
  63. class TokenInterceptor extends Interceptor {
  64. // 这里假设您有一个方法来从安全存储中获取Token
  65. Future<String?> getToken() async {
  66. // 从您存储Token的地方获取Token,例如从SharedPreferences或SecureStorage
  67. String? token = await SharedPreferencesUtil().getString("token");
  68. return token;
  69. //return "Your_Token";
  70. }
  71. @override
  72. Future<void> onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
  73. final token = await getToken();
  74. if (token != null) {
  75. options.headers["Authorization"] = "Bearer $token";
  76. }
  77. return super.onRequest(options, handler);
  78. }
  79. }
  80. class CustomInterceptors extends Interceptor {
  81. int _retryCount = 0;
  82. final List<String> _backupUrls = ['https://api.androidrj02.top','https://api.androidrj88.com','https://user.jyjksmd.top','https://api.androidrj03.top'];
  83. final Dio _dio; // 添加 Dio 作为参数
  84. CustomInterceptors(this._dio);
  85. Future<bool> isConnected() async {
  86. var connectivityResult = await (Connectivity().checkConnectivity());
  87. return connectivityResult != ConnectivityResult.none;
  88. }
  89. void resetRetryCount() {
  90. _retryCount = 0;
  91. }
  92. @override
  93. Future<void> onError(DioError err, ErrorInterceptorHandler handler) async {
  94. // 检查网络连接状态
  95. bool isConnectNetWork = await isConnected();
  96. if (!isConnectNetWork) {
  97. // 无网络连接,设置友好的错误消息
  98. err.error = AppException(message: "当前网络不可用,请检查您的网络");
  99. return handler.next(err);
  100. } else if (err.error is SocketException || err.type == DioErrorType.other) {
  101. if (_retryCount < _backupUrls.length) {
  102. // 有网络连接但请求失败,尝试使用备用地址
  103. err.requestOptions.baseUrl = _backupUrls[_retryCount];
  104. try {
  105. final Response response = await _dio.fetch(err.requestOptions);
  106. return handler.resolve(response);
  107. } catch (e) {
  108. if (e is DioError) {
  109. _retryCount++;
  110. return onError(e, handler); // Recursive call
  111. } else {
  112. // Handle other exceptions if needed or rethrow them
  113. rethrow;
  114. }
  115. }
  116. }
  117. }
  118. // 其他错误,统一处理
  119. AppException appException = AppException.create(err);
  120. debugPrint('DioError===: ${appException.toString()}');
  121. err.error = appException;
  122. return handler.next(err);
  123. }
  124. }
  125. class AppException implements Exception {
  126. final int? statusCode; // 添加了 statusCode
  127. final String message;
  128. AppException({required this.message,this.statusCode});
  129. static AppException create(DioError err) {
  130. switch (err.type) {
  131. case DioErrorType.cancel:
  132. return AppException(message: '请求被取消');
  133. case DioErrorType.connectTimeout:
  134. return AppException(message: '连接超时');
  135. case DioErrorType.sendTimeout:
  136. return AppException(message: '请求超时');
  137. case DioErrorType.receiveTimeout:
  138. return AppException(message: '响应超时');
  139. case DioErrorType.response:
  140. return AppException(
  141. message: '服务器返回异常,状态码:${err.response?.statusCode}',
  142. statusCode: err.response?.statusCode, // 设置statusCode,即使在default中也可以选择设置
  143. );
  144. case DioErrorType.other:
  145. return AppException(
  146. message: '未知错误: ${err.message}',
  147. statusCode: err.response?.statusCode, // 设置statusCode,即使在default中也可以选择设置
  148. );
  149. default:
  150. return AppException(
  151. message: err.message,
  152. statusCode: err.response?.statusCode, // 设置statusCode,即使在default中也可以选择设置
  153. );
  154. }
  155. }
  156. @override
  157. String toString() {
  158. return message;
  159. }
  160. }
  161. extension DioClientExtension on DioClient {
  162. Future<dynamic> get(String path, {Map<String, dynamic>? queryParameters}) async {
  163. final response = await _dio.get(path, queryParameters: queryParameters);
  164. return _handleResponse(response);
  165. }
  166. Future<dynamic> post(String path, {Map<String, dynamic>? data}) async {
  167. final response = await _dio.post(path, data: data);
  168. return _handleResponse(response);
  169. }
  170. Future<dynamic> put(String path, {Map<String, dynamic>? data}) async {
  171. final response = await _dio.put(path, data: data);
  172. return _handleResponse(response);
  173. }
  174. Future<void> download(String urlPath, String savePath) async {
  175. await _dio.download(urlPath, savePath);
  176. }
  177. dynamic _handleResponse(Response response) {
  178. if (response.data is List) {
  179. return response.data as List<dynamic>;
  180. } else if (response.data is Map) {
  181. return response.data as Map<String, dynamic>;
  182. } else {
  183. throw Exception('Unsupported data type');
  184. }
  185. }
  186. }