From a5cc3fdc5b4f24749e5018f5bbc9bb20a638212f Mon Sep 17 00:00:00 2001 From: hailin Date: Thu, 26 Feb 2026 12:21:57 -0800 Subject: [PATCH] =?UTF-8?q?fix(mobile-app):=20=E4=BF=AE=E5=A4=8D=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E8=B4=A6=E5=8F=B7=E6=97=B6=20token=20=E8=BF=87?= =?UTF-8?q?=E6=9C=9F=E5=AF=BC=E8=87=B4=E8=87=AA=E5=8A=A8=E9=80=80=E5=87=BA?= =?UTF-8?q?=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因:switchToAccount() 流程中,定时器在 _clearCurrentAccountData() 之后才停止。clear 阶段会删除 token,但此时定时器仍在运行, in-flight 的 API 请求收到 401 → 触发 _handleTokenExpired() → 调用 logoutCurrentAccount() 把正在恢复的新账号数据全部清掉 → 用户被自动踢到登录页面。 修复:将 onBeforeRestore 回调(停止定时器)移到 _clearCurrentAccountData() 之前执行,确保所有 API 请求停止后再清除 token。 修改前: save → clear(删token) → 停定时器 → restore 修改后: save → 停定时器 → clear(删token) → restore Co-Authored-By: Claude Opus 4.6 --- .../core/services/multi_account_service.dart | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/frontend/mobile-app/lib/core/services/multi_account_service.dart b/frontend/mobile-app/lib/core/services/multi_account_service.dart index 5da9ed01..a29a341c 100644 --- a/frontend/mobile-app/lib/core/services/multi_account_service.dart +++ b/frontend/mobile-app/lib/core/services/multi_account_service.dart @@ -215,16 +215,16 @@ class MultiAccountService { /// 切换到指定账号 /// 返回 true 表示切换成功 /// - /// [onBeforeRestore] 在清除旧数据之后、恢复新账号数据之前调用, - /// 用于重置内存中的 Provider 状态(如 authProvider、walletStatusProvider 等), - /// 确保不会有前一个账号的内存数据残留。 + /// [onBeforeRestore] 在保存当前账号数据之后、清除存储之前调用, + /// 用于停止所有定时器和 Provider 轮询,确保在 token 被清除前没有 in-flight 的 API 请求, + /// 防止请求收到 401 后触发 tokenExpired → 自动退出登录。 /// /// 切换流程: /// 1. 验证目标账号存在 /// 2. 验证目标账号数据完整性 /// 3. 保存当前账号数据到账号专用存储 + /// 3.5 调用 onBeforeRestore 停止定时器(必须在 clear 之前,防止 401 触发自动退出) /// 4. 清除当前存储空间(确保干净环境) - /// 4.5 调用 onBeforeRestore 重置内存状态 /// 5. 从账号专用存储恢复目标账号数据 /// 6. 设置当前账号标记 /// 7. 更新遥测和错误追踪服务的用户信息 @@ -254,15 +254,17 @@ class MultiAccountService { debugPrint('$_tag switchToAccount() - 已保存当前账号数据: $currentId'); } - // 4. 清除当前存储空间(确保干净环境,避免数据残留) - await _clearCurrentAccountData(); - - // 4.5 重置内存中的 Provider 状态(避免前账号数据残留在内存中) + // 3.5 停止所有定时器(必须在 clear 之前!) + // 原因:clear 会删除 token,如果定时器还在跑,in-flight 的 API 请求收到 401 + // → 触发 _handleTokenExpired → logoutCurrentAccount() 把恢复中的数据全部清掉 if (onBeforeRestore != null) { await onBeforeRestore(); - debugPrint('$_tag switchToAccount() - 已重置内存状态'); + debugPrint('$_tag switchToAccount() - 已停止定时器和重置内存状态'); } + // 4. 清除当前存储空间(确保干净环境,避免数据残留) + await _clearCurrentAccountData(); + // 5. 从账号专用存储恢复目标账号数据 await _restoreAccountData(userSerialNum);