Amplify集成Cognito时tokenRefresh事件高频重复触发问题
问题背景
使用如下代码监控Amplify+Cognito认证流程:
const handleHubEvent = useCallback((capsule) => { const event = capsule?.payload?.event; try { switch(event){ case 'signIn_start': case 'signIn': case 'tokenRefresh': const user = await auth.currentAuthenticatedUser(); setCurrentUser(user); break; case 'signOut': case 'tokenRefresh_failure': setCurrentUser(null); break; } } catch (e) { console.log("Error: ", e); setCurrentUser(null); } }, []); useEffect(() => { Hub.listen('auth', handleHubEvent); Hub.dispatch('auth', { event: 'signIn_start' }); return () => Hub.remove('auth', handleHubEvent); }, []);
运行后出现异常:
- 页面运行数小时到达会话过期节点后,事件回调
handleHubEvent持续高频触发,频率约每秒7次 - 浏览器网络面板可观测到大量发往
cognito-idp.ap-southeast-2.amazonaws.com的请求 - 已确认
Hub.listen仅执行一次,不存在同一事件绑定多个监听器的情况 - 刷新页面后异常行为仍然存在,仅删除站点Cookie后重新登录可临时恢复
代码逻辑错误说明
代码存在4处明确问题,直接触发上述高频死循环现象:
- 基础语法错误:
handleHubEvent未声明为async函数,内部直接使用await调用异步方法会抛出语法异常,导致try/catch块、分支内的状态重置逻辑完全失效,异常发生时无法按预期执行兜底逻辑。 - 事件递归触发逻辑:
signIn_start、signIn、tokenRefresh三个事件分支均调用auth.currentAuthenticatedUser(),该方法检测到Access Token过期时会自动执行Token刷新流程,执行过程中会再次向Hub派发tokenRefresh事件,直接形成「回调触发→调用Auth方法→派发新事件→再次触发回调」的无限循环。 - 无效凭证残留:
tokenRefresh_failure分支和catch块仅修改了前端内存中的用户状态,未调用auth.signOut()清理Amplify存储在Cookie、LocalStorage中的无效凭证。页面刷新后Amplify初始化阶段会读取这些残留凭证,反复发起无效的Token刷新请求,这是刷新页面后异常仍不消失的核心原因。 - 冗余触发逻辑:useEffect挂载时主动dispatch
signIn_start事件属于多余操作,Amplify初始化时会自动检测本地凭证状态并派发对应Auth事件,手动触发会在凭证异常场景下放大循环调用的频率。
修复后参考代码
const handleHubEvent = useCallback(async (capsule) => { const event = capsule?.payload?.event; try { switch(event){ case 'signIn': case 'tokenRefresh': const user = await auth.currentAuthenticatedUser(); setCurrentUser(user); break; case 'signIn_start': // 移除该分支的重复调用,避免循环触发 break; case 'signOut': case 'tokenRefresh_failure': // 主动清理本地无效凭证 await auth.signOut({ global: false }); setCurrentUser(null); break; } } catch (e) { console.log("Auth handle error: ", e); // 异常场景下同步清理凭证 await auth.signOut({ global: false }); setCurrentUser(null); } }, []); useEffect(() => { Hub.listen('auth', handleHubEvent); // 移除手动dispatch的signIn_start事件,避免重复触发 return () => Hub.remove('auth', handleHubEvent); }, []);
内容的提问来源于stack exchange,提问作者alx
相关产品推荐
相关产品推荐

