2024-03-18 13:23:58 +08:00
|
|
|
|
import 'dart:convert';
|
2024-03-31 17:13:29 +08:00
|
|
|
|
import 'package:get/get.dart' as get_package;
|
2024-03-18 13:23:58 +08:00
|
|
|
|
import 'package:dio/dio.dart';
|
2024-03-20 15:26:49 +08:00
|
|
|
|
import 'package:sk_base_mobile/models/base_response.dart';
|
2024-03-18 13:23:58 +08:00
|
|
|
|
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';
|
|
|
|
|
|
2024-03-31 17:13:29 +08:00
|
|
|
|
class DioService extends get_package.GetxService {
|
|
|
|
|
static DioService get to => get_package.Get.find();
|
2024-03-18 13:23:58 +08:00
|
|
|
|
static Dio get dio => _dio;
|
|
|
|
|
static late Dio _dio;
|
2024-03-27 11:06:01 +08:00
|
|
|
|
List<String> whiteList = [Urls.login];
|
2024-03-18 13:23:58 +08:00
|
|
|
|
BaseOptions dioBaseOptions = BaseOptions(
|
2024-03-28 15:13:27 +08:00
|
|
|
|
connectTimeout: const Duration(seconds: GloablConfig.DIO_TIMEOUT),
|
2024-03-31 17:13:29 +08:00
|
|
|
|
baseUrl: GloablConfig.BASE_URL,
|
2024-03-18 13:23:58 +08:00
|
|
|
|
followRedirects: true);
|
|
|
|
|
|
|
|
|
|
late CancelToken cancelToken;
|
|
|
|
|
|
|
|
|
|
/// Initialize the dio instance
|
|
|
|
|
Future<DioService> 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)) {
|
|
|
|
|
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.
|
2024-03-26 11:35:39 +08:00
|
|
|
|
await SnackBarUtil().error(TextEnum.serverErrorMsg);
|
|
|
|
|
} else if (e.type == DioExceptionType.connectionError) {
|
|
|
|
|
// It occurs when url is opened timeout.
|
|
|
|
|
await SnackBarUtil().error(TextEnum.serverErrorMsg);
|
2024-03-18 13:23:58 +08:00
|
|
|
|
} 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.',
|
|
|
|
|
// );
|
2024-03-31 17:13:29 +08:00
|
|
|
|
} else if (e.type == DioExceptionType.badResponse) {
|
2024-03-18 13:23:58 +08:00
|
|
|
|
// 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) {
|
|
|
|
|
// dio.lock();
|
|
|
|
|
LoggerUtil().error('[Service-dio] logout:${e.response}');
|
2024-04-07 17:32:46 +08:00
|
|
|
|
Future.delayed(Duration(seconds: 1), () {
|
|
|
|
|
AuthStore().logout(force: true);
|
|
|
|
|
});
|
2024-03-28 15:13:27 +08:00
|
|
|
|
SnackBarUtil().error('请重新登录');
|
2024-03-18 13:23:58 +08:00
|
|
|
|
} 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']);
|
|
|
|
|
}
|
2024-03-31 17:13:29 +08:00
|
|
|
|
} else if (e.type == DioExceptionType.cancel) {
|
2024-03-18 13:23:58 +08:00
|
|
|
|
// 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) {
|
2024-03-19 10:02:20 +08:00
|
|
|
|
options.headers["Authorization"] = "Bearer $token";
|
2024-03-18 13:23:58 +08:00
|
|
|
|
}
|
|
|
|
|
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)) {
|
2024-03-31 17:13:29 +08:00
|
|
|
|
LoggerUtil().info(
|
|
|
|
|
'[Service-dio] url: ${options.path}, params: ${jsonEncode(options.queryParameters)}, body: ${jsonEncode(options.data)}, Header:${jsonEncode(options.headers)}');
|
2024-03-18 13:23:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handler.next(options);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void onResponse(Response response, ResponseInterceptorHandler handler) async {
|
|
|
|
|
/* LoggerUtil().info('[Service-dio] ${response.data}'); */
|
2024-04-07 17:32:46 +08:00
|
|
|
|
|
2024-03-18 13:23:58 +08:00
|
|
|
|
if (whiteList.contains(response.requestOptions.path)) {
|
|
|
|
|
handler.next(response);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2024-03-26 17:03:27 +08:00
|
|
|
|
if (response.data != null && response.data is Map) {
|
2024-03-26 11:35:39 +08:00
|
|
|
|
if (response.data['code'] == 200) {
|
|
|
|
|
if (GloablConfig.DEBUG) LoggerUtil().info(response.data['data']);
|
|
|
|
|
response.data = response.data['data'];
|
|
|
|
|
// 分页数据处理
|
|
|
|
|
if (response.data != null &&
|
2024-03-26 17:10:14 +08:00
|
|
|
|
response.data is Map &&
|
2024-03-26 11:35:39 +08:00
|
|
|
|
response.data['meta'] != null &&
|
|
|
|
|
response.data['items'] != null) {
|
|
|
|
|
response.data = PaginationData.fromJson(response.data);
|
2024-03-18 13:23:58 +08:00
|
|
|
|
}
|
2024-03-26 17:03:27 +08:00
|
|
|
|
} else if (response.data['message'] != null) {
|
2024-03-26 11:35:39 +08:00
|
|
|
|
await SnackBarUtil().error(response.data['message']);
|
2024-03-18 13:23:58 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
handler.next(response);
|
|
|
|
|
}
|
|
|
|
|
}
|