fix(client): 修复启动时 token 刷新导致 Dio adapter closed 崩溃
apiClientProvider 改用 select(isLoggedIn),token refresh 不触发 provider 重建,避免旧 Dio 被 close 后仍执行 fetch。同时在拦截器内原地更新 _dio.options.headers,保证后续请求使用新 token。 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -14,25 +14,21 @@ final _publicDio = Dio(BaseOptions(
|
||||
));
|
||||
|
||||
final apiClientProvider = Provider<ApiClient>((ref) {
|
||||
final authState = ref.watch(authStateProvider);
|
||||
final myToken = authState.user?.accessToken;
|
||||
// 只监听登录/登出,不监听 token 内容变化。
|
||||
// token refresh 只改 accessToken,isLoggedIn 不变,provider 不重建,
|
||||
// 避免旧 Dio 被 close 后还在执行 fetch 导致 "adapter was closed"。
|
||||
ref.watch(authStateProvider.select((s) => s.isLoggedIn));
|
||||
final user = ref.read(authStateProvider).user;
|
||||
|
||||
final client = ApiClient(
|
||||
token: myToken,
|
||||
refreshToken: authState.user?.refreshToken,
|
||||
token: user?.accessToken,
|
||||
refreshToken: user?.refreshToken,
|
||||
onTokenRefreshed: (newToken) {
|
||||
debugPrint('[ApiClient] token refreshed');
|
||||
if (ref.read(authStateProvider).user?.accessToken == myToken) {
|
||||
ref.read(authStateProvider.notifier).updateAccessToken(newToken);
|
||||
}
|
||||
ref.read(authStateProvider.notifier).updateAccessToken(newToken);
|
||||
},
|
||||
onAuthFailed: () {
|
||||
debugPrint('[ApiClient] onAuthFailed! myToken prefix: ${(myToken ?? '').substring(0, (myToken ?? '').length.clamp(0, 20))}');
|
||||
if (ref.read(authStateProvider).user?.accessToken == myToken) {
|
||||
debugPrint('[ApiClient] calling logout()');
|
||||
if (ref.read(authStateProvider).isLoggedIn) {
|
||||
ref.read(authStateProvider.notifier).logout();
|
||||
} else {
|
||||
debugPrint('[ApiClient] skipping logout (stale client)');
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -77,8 +73,10 @@ class ApiClient {
|
||||
});
|
||||
final newToken =
|
||||
resp.data['data']['access_token'] as String;
|
||||
// 原地更新 Dio 默认 headers,后续所有请求生效
|
||||
_dio.options.headers['Authorization'] = 'Bearer $newToken';
|
||||
if (!_disposed) onTokenRefreshed?.call(newToken);
|
||||
// 用新 token 重试原请求
|
||||
// 用新 token 重试原请求(此时 _dio 仍存活,不会 adapter closed)
|
||||
final opts = e.requestOptions;
|
||||
opts.headers['Authorization'] = 'Bearer $newToken';
|
||||
final retryResp = await _dio.fetch(opts);
|
||||
|
||||
Reference in New Issue
Block a user