import 'dart:convert'; import 'package:get/get.dart' as Get; import 'package:dio/dio.dart'; import 'package:sk_base_mobile/util/logger_util.dart'; import 'package:sk_base_mobile/config.dart'; import 'package:sk_base_mobile/services/storage.service.dart'; import 'package:sk_base_mobile/store/auth.store.dart'; import 'package:sk_base_mobile/util/snack_bar.util.dart'; import '../constants/constants.dart'; class DioService extends Get.GetxService { static DioService get to => Get.Get.find(); static Dio get dio => _dio; static late Dio _dio; List whiteList = [Urls.googleTranslate]; BaseOptions dioBaseOptions = BaseOptions( connectTimeout: const Duration(minutes: 10), baseUrl: '${GloablConfig.BASE_URL}', followRedirects: true); late CancelToken cancelToken; /// Initialize the dio instance Future init() async { _dio = Dio(dioBaseOptions); _dio.interceptors.add(InterceptorsWrapper( onRequest: onRequest, onResponse: onResponse, onError: onError)); cancelToken = CancelToken(); return this; } void onError(DioException e, ErrorInterceptorHandler handler) async { if (whiteList.contains(e.requestOptions.path)) { await SnackBarUtil().error(e.message); return handler.next(e); } if (GloablConfig.DEBUG) { LoggerUtil().info( "[Service-dio] Error found on ${e.requestOptions.method} ${e.requestOptions.uri}"); } if (e.type == DioExceptionType.connectionTimeout) { // It occurs when url is opened timeout. await SnackBarUtil().error( 'The server is busy, please try again.', ); } else if (e.type == DioExceptionType.sendTimeout) { // It occurs when url is sent timeout. // await SnackBarUtil().error( // 'The server is busy, please try again.', // ); } else if (e.type == DioExceptionType.receiveTimeout) { //It occurs when receiving timeout // await SnackBarUtil().error( // 'The server is busy, please try again.', // ); } else if (e.type == DioErrorType.badResponse) { // When the server response, but with a incorrect status, such as 404, 503... if (e.response?.statusCode == 400) { await SnackBarUtil().error( e.response?.data['message'], ); } else if (e.response?.statusCode == 401) { await SnackBarUtil().error( 'Your role at this season has been updated. Please log in again.', ); // dio.lock(); LoggerUtil().error('[Service-dio] logout:${e.response}'); await AuthStore().logout(force: true); } else if (e.response?.statusCode == 403) { await SnackBarUtil().error( '${e.response?.data['message']}.', ); // await AuthStore().logout(force: true); } else if (e.response?.statusCode == 409) { await SnackBarUtil().error(e.response?.data['message']); } else if (e.response?.statusCode == 500) { await SnackBarUtil() .error('The server is busy, please try again later'); } else if (e.response?.statusCode == 404) { LoggerUtil().error('[Service-dio] logout:${e.response}'); // await AuthStore().logout(force: true); } else if (e.response?.statusCode == 422) { await SnackBarUtil().error(e.response?.data['message']); } } else if (e.type == DioErrorType.cancel) { // When the request is cancelled, dio will throw a error with this type. LoggerUtil().error("[Service-dio] 请求取消"); } else { //DEFAULT Default error type, Some other Error. In this case, you can read the DioError.error if it is not null. LoggerUtil().error("[Service-dio] 未知错误:$e"); if ((e.error?.toString() ?? '') .toString() .contains("HandshakeException")) { // Just a network failure } else { await SnackBarUtil().error(e.error.toString()); // AuthStore().logout(force: true); } } return handler.next(e); } whiteListFilter(String url) => url.endsWith('_allow_anonymous=true'); void onRequest(RequestOptions options, RequestInterceptorHandler handler) { if (!whiteList.contains(options.path)) { String? token = StorageService.to.getString(CacheKeys.token, isWithUser: false); if (options.headers['Authorization'] == null && token != null) { options.headers["Authorization"] = "Bearer$token"; } options.headers['device-id'] = StorageService.to.getString( CacheKeys.deviceUUID, isWithUser: false); // 设备id或者udid,保证当前设备唯一值。 options.headers["platform"] = "iOS"; options.headers['model'] = StorageService.to .getString(CacheKeys.deviceModel, isWithUser: false); // 设备型号 } if (GloablConfig.DEBUG && (options.data is! FormData)) { LoggerUtil().info('[Service-dio] url: ${options.path}' + ', params: ${jsonEncode(options.queryParameters)}' + ', body: ${jsonEncode(options.data)}, Header:${jsonEncode(options.headers)}'); } handler.next(options); } void onResponse(Response response, ResponseInterceptorHandler handler) async { /* LoggerUtil().info('[Service-dio] ${response.data}'); */ if (whiteList.contains(response.requestOptions.path)) { handler.next(response); return; } if (response.data != null) { try { dynamic responseData = response.data; if (response.data is String) { responseData = jsonDecode(response.data); } switch (responseData['code']) { case 0: handler.next(response); return; // 其他设备登录 case 10010304: await AuthStore().logout(force: true); await SnackBarUtil() .error('Other devices have logged in, please log in again.'); break; case 100103: case 10010303: await AuthStore().logout(force: true); await SnackBarUtil() .error('Login has timed out, please log in again.'); break; case 10010301: await AuthStore().logout(force: true); await SnackBarUtil().error('Token can not empty'); break; default: await SnackBarUtil() .error('${responseData['key']}: ${responseData['msg']}'); break; } } catch (e) { printError(info: e.toString()); } } handler.next(response); } }