dio_client.dart 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  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. //token
  32. _dio.interceptors.add(TokenInterceptor());
  33. // 添加拦截器
  34. _dio.interceptors.add(CustomInterceptors());
  35. // 添加响应拦截器
  36. _dio.interceptors.add(InterceptorsWrapper(
  37. onResponse: (Response<dynamic> response, ResponseInterceptorHandler handler) {
  38. final responseData = response.data as Map<String, dynamic>;
  39. if (responseData['ret'] == 1) {
  40. handler.next(
  41. Response<dynamic>(
  42. data: responseData['data'],
  43. headers: response.headers,
  44. requestOptions: response.requestOptions,
  45. statusCode: response.statusCode,
  46. ),
  47. );
  48. } else {
  49. handler.reject(
  50. DioError(
  51. requestOptions: response.requestOptions,
  52. error: AppException(message: responseData['msg'] ?? 'Unknown Error'),
  53. ),
  54. );
  55. }
  56. },
  57. ));
  58. }
  59. Dio get dio => _dio;
  60. }
  61. class TokenInterceptor extends Interceptor {
  62. // 这里假设您有一个方法来从安全存储中获取Token
  63. Future<String?> getToken() async {
  64. // 从您存储Token的地方获取Token,例如从SharedPreferences或SecureStorage
  65. String? token = await SharedPreferencesUtil().getString("token");
  66. return token;
  67. //return "Your_Token";
  68. }
  69. @override
  70. Future<void> onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
  71. final token = await getToken();
  72. if (token != null) {
  73. options.headers["Authorization"] = "Bearer $token";
  74. }
  75. return super.onRequest(options, handler);
  76. }
  77. }
  78. class CustomInterceptors extends Interceptor {
  79. int _retryCount = 0;
  80. final List<String> _backupUrls = ['https://api.androidrj03.top', 'https://api.androidrj88.com'];
  81. Future<bool> isConnected() async {
  82. var connectivityResult = await (Connectivity().checkConnectivity());
  83. return connectivityResult != ConnectivityResult.none;
  84. }
  85. @override
  86. Future<void> onError(DioError err, ErrorInterceptorHandler handler) async {
  87. // 检查网络连接状态
  88. bool isConnectNetWork = await isConnected();
  89. if (!isConnectNetWork) {
  90. // 无网络连接,设置友好的错误消息
  91. err.error = AppException(message: "当前网络不可用,请检查您的网络");
  92. return handler.next(err);
  93. } else if (err.error is SocketException || err.type == DioErrorType.other) {
  94. if (_retryCount < _backupUrls.length) {
  95. // 有网络连接但请求失败,尝试使用备用地址
  96. err.requestOptions.baseUrl = _backupUrls[_retryCount];
  97. _retryCount++;
  98. try {
  99. final Dio dio = Dio();
  100. final Response response = await dio.request<dynamic>(
  101. err.requestOptions.path,
  102. cancelToken: err.requestOptions.cancelToken,
  103. data: err.requestOptions.data,
  104. onReceiveProgress: err.requestOptions.onReceiveProgress,
  105. onSendProgress: err.requestOptions.onSendProgress,
  106. queryParameters: err.requestOptions.queryParameters,
  107. options: Options(
  108. method: err.requestOptions.method,
  109. headers: err.requestOptions.headers,
  110. contentType: err.requestOptions.contentType,
  111. responseType: err.requestOptions.responseType,
  112. ),
  113. );
  114. return handler.resolve(response);
  115. } catch (e) {
  116. return handler.next(err);
  117. }
  118. }
  119. }
  120. // 其他错误,统一处理
  121. AppException appException = AppException.create(err);
  122. debugPrint('DioError===: ${appException.toString()}');
  123. err.error = appException;
  124. return handler.next(err);
  125. }
  126. }
  127. class AppException implements Exception {
  128. final String message;
  129. AppException({required this.message});
  130. static AppException create(DioError err) {
  131. switch (err.type) {
  132. case DioErrorType.cancel:
  133. return AppException(message: '请求被取消');
  134. case DioErrorType.connectTimeout:
  135. return AppException(message: '连接超时');
  136. case DioErrorType.sendTimeout:
  137. return AppException(message: '请求超时');
  138. case DioErrorType.receiveTimeout:
  139. return AppException(message: '响应超时');
  140. case DioErrorType.response:
  141. return AppException(
  142. message: '服务器返回异常,状态码:${err.response?.statusCode}',
  143. );
  144. case DioErrorType.other:
  145. return AppException(
  146. message: '未知错误: ${err.message}',
  147. );
  148. default:
  149. return AppException(
  150. message: err.message,
  151. );
  152. }
  153. }
  154. @override
  155. String toString() {
  156. return message;
  157. }
  158. }
  159. extension DioClientExtension on DioClient {
  160. Future<dynamic> get(String path, {Map<String, dynamic>? queryParameters}) async {
  161. final response = await _dio.get(path, queryParameters: queryParameters);
  162. return _handleResponse(response);
  163. }
  164. Future<dynamic> post(String path, {Map<String, dynamic>? data}) async {
  165. final response = await _dio.post(path, data: data);
  166. return _handleResponse(response);
  167. }
  168. Future<dynamic> put(String path, {Map<String, dynamic>? data}) async {
  169. final response = await _dio.put(path, data: data);
  170. return _handleResponse(response);
  171. }
  172. Future<void> download(String urlPath, String savePath) async {
  173. await _dio.download(urlPath, savePath);
  174. }
  175. dynamic _handleResponse(Response response) {
  176. if (response.data is List) {
  177. return response.data as List<dynamic>;
  178. } else if (response.data is Map) {
  179. return response.data as Map<String, dynamic>;
  180. } else {
  181. throw Exception('Unsupported data type');
  182. }
  183. }
  184. }