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 ErrorInterceptor extends InterceptorsWrapper {
bool _isRedirectingToLogin = false;
bool _isRefreshingToken = false;
Completer<void>? _refreshCompleter;
@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 && _refreshCompleter != null) {
logger.w("已有刷新任务,等待刷新完成后重试请求...");
try {
await _refreshCompleter!.future;
} catch (e) {
logger.e("等待刷新任务失败: $e");
return handler.reject(
DioException(
requestOptions: response.requestOptions,
error: "刷新 token 失败(等待阶段): $e",
),
);
}
final retrier = DioRequestRetrier(
requestOptions: response.requestOptions,
);
final retryResponse = await retrier.retry();
return handler.resolve(retryResponse);
}
if (!_isRefreshingToken) {
_isRefreshingToken = true;
_refreshCompleter = Completer<void>();
logger.w("开始刷新 token...");
try {
if (!(_refreshCompleter?.isCompleted ?? true)) {
_refreshCompleter!.complete();
}
_isRefreshingToken = false;
final retrier = DioRequestRetrier(
requestOptions: response.requestOptions,
);
final retryResponse = await retrier.retry();
return handler.resolve(retryResponse);
} catch (e) {
logger.e("刷新 token 失败: $e");
if (!(_refreshCompleter?.isCompleted ?? true)) {
_refreshCompleter!.completeError(e);
}
_isRefreshingToken = false;
if (!_isRedirectingToLogin && Get.currentRoute != Routes.LOGIN) {
_isRedirectingToLogin = true;
Future.microtask(() {
Get.offAllNamed(Routes.LOGIN);
_isRedirectingToLogin = false;
});
}
return handler.reject(
DioException(
requestOptions: response.requestOptions,
error: "刷新 token 失败",
),
);
} finally {
_isRefreshingToken = false;
_refreshCompleter = null;
}
}
}
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);
}
}
}