import 'dart:async';
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:get/get.dart' hide Response;
import 'package:myapp/app/constants/app_values.dart';
import 'package:myapp/app/model/userInfo.dart';
import 'package:myapp/app/network/dio_request_retrier.dart';
import 'package:myapp/app/network/repositories/account_repository_impl.dart';
import 'package:myapp/app/routes/app_pages.dart';
import 'package:myapp/app/service/storage_service.dart';
import 'package:myapp/app/utils/logger/logger.dart';
class _PendingRequest {
final RequestOptions options;
final Completer<Response> completer;
_PendingRequest(this.options, this.completer);
}
class ErrorInterceptor extends InterceptorsWrapper {
bool _isRedirectingToLogin = false;
bool _isRefreshingToken = false;
final List<_PendingRequest> _pendingRequests = [];
@override
void onResponse(Response response, ResponseInterceptorHandler handler) async {
logger.i(response.requestOptions.path);
if (response.data is Map<String, dynamic> &&
response.data['code'] == 303 &&
response.data['data']['type'] == "need login") {
if (_isRefreshingToken) {
logger.w("已有刷新任务,等待刷新完成后重试请求...");
final completer = Completer<Response>();
_pendingRequests.add(
_PendingRequest(response.requestOptions, completer),
);
try {
final res = await completer.future;
handler.resolve(res);
} catch (e) {
logger.e("等待刷新任务失败: $e");
return handler.reject(
DioException(
requestOptions: response.requestOptions,
error: "刷新 token 失败(等待阶段): $e",
),
);
}
return;
}
if (!_isRefreshingToken) {
_isRefreshingToken = true;
logger.w("开始刷新 token...");
try {
final pending = List<_PendingRequest>.from(_pendingRequests);
_pendingRequests.clear();
for (final pendingRequest in pending) {
final retrier = DioRequestRetrier(
requestOptions: pendingRequest.options,
);
try {
final retryResponse = await retrier.retry();
pendingRequest.completer.complete(retryResponse);
} catch (e) {
pendingRequest.completer.completeError(e);
}
}
final retrier = DioRequestRetrier(
requestOptions: response.requestOptions,
);
final retryResponse = await retrier.retry();
return handler.resolve(retryResponse);
} catch (e) {
logger.e("刷新 token 失败: $e");
for (final pendingRequest in _pendingRequests) {
pendingRequest.completer.completeError(e);
}
_pendingRequests.clear();
if (!_isRedirectingToLogin && Get.currentRoute != Routes.LOGIN) {
_isRedirectingToLogin = true;
Future.microtask(() {
Get.offAllNamed(Routes.LOGIN);
_isRedirectingToLogin = false;
});
}
return handler.reject(
DioException(
requestOptions: response.requestOptions,
error: "身份过期请重新登陆",
),
);
} finally {
_isRefreshingToken = false;
}
}
}
super.onResponse(response, handler);
}
@override
void onError(DioException e, ErrorInterceptorHandler handler) {
if (e.response?.statusCode == 401) {
if (!_isRedirectingToLogin && Get.currentRoute != Routes.LOGIN) {
_isRedirectingToLogin = true;
Future.microtask(() {
Get.offAllNamed(Routes.LOGIN);
_isRedirectingToLogin = false;
});
}
super.onError(e, handler);
} else if (e.type == DioExceptionType.unknown) {
debugPrint("网络错误: ${e.message}");
handler.reject(e);
} else {
super.onError(e, handler);
}
}
}