dio_client.dart 7.5 KB

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