如何处理认证API并发请求:刷新access token时仅首个执行其余等待
并发请求下JWT令牌重复刷新优化方案
核心思路是新增一个全局的刷新请求锁(基于Promise实现),无需复杂的请求队列,即可实现仅触发一次刷新、其余请求等待的效果。
具体修改步骤
- 在全局
useAuthhook中新增ref,存储正在进行中的刷新令牌请求Promise,避免重复发起请求:
// 放在useAuth内部和其他ref同级的位置 const refreshTokenPendingRef = useRef(null);
- 改造
retrieveAccessToken函数,新增锁判断逻辑:
const retrieveAccessToken = async (url, override = false) => { if (!isLoggedIn || override === true) { // 已有正在进行的刷新请求,直接返回该Promise,无需重复发起 if (refreshTokenPendingRef.current) { return refreshTokenPendingRef.current; } // 无进行中的刷新请求,创建新请求并赋值给ref上锁 refreshTokenPendingRef.current = fetch(url, { method: 'GET', }).then((res) => { if (res.status >= 300 && res.status !== 401) throw new Error('API Client error'); return res.json(); }).then((apiResponse) => { console.log('setting access token'); setUser(apiResponse?.user); return isLoggedInRef.current === true; }).catch((err) => { // 刷新失败时清空锁,允许后续请求重试 refreshTokenPendingRef.current = null; throw err; }).finally(() => { // 请求完成后无论成功失败,统一清空锁 refreshTokenPendingRef.current = null; }); return refreshTokenPendingRef.current; } return null; };
逻辑说明
- 首个检测到令牌过期的请求调用
retrieveAccessToken时,refreshTokenPendingRef为空,会发起真实的刷新请求,同时将请求Promise存入ref完成上锁 - 后续并发的其他过期请求调用
retrieveAccessToken时,会直接等待已有Promise完成,不会发起新的刷新请求 - 刷新请求无论成功失败,都会在结束后自动解锁,不影响后续正常的令牌刷新逻辑
该方案无需修改其他业务代码,改造完成后只会触发一次令牌刷新请求,不会再出现重复调用的问题。
内容的提问来源于stack exchange,提问作者anastymous
相关产品推荐
相关产品推荐

