如何在收到401响应后自动刷新令牌并重试fetch请求(避免代码重复)
如何在收到401响应后自动刷新令牌并重试fetch请求(避免代码重复)
我完全理解你的痛点——重复写一模一样的fetch代码块不仅冗余,后续维护时改一处要同步改多处,很容易出错。咱们可以通过抽取可复用请求逻辑或者封装通用请求包装器两种方式来彻底解决这个问题,下面给你两种实用的落地方案:
方案1:针对当前请求抽取独立函数(快速适配你的场景)
先把acceptRequest里的核心请求逻辑抽成一个单独的异步函数,这样不管是第一次请求还是401后的重试,都直接调用这个函数即可,完全消除代码重复:
// 抽取核心请求逻辑为独立可复用函数 const sendAcceptRequest = async (enemyId) => { return fetch(`${process.env.NEXT_PUBLIC_SOCKET_SERVER_URL}/acceptRequest`, { method: "POST", body: JSON.stringify({ id: enemyId }), credentials: "include", headers: { "Content-Type": "application/json", }, }); }; const acceptRequest = async () => { try { let res = await sendAcceptRequest(enemyid); // 第一次请求成功的处理 if (res.status === 200) { toast("Working"); return; } // 处理401未授权场景 if (res.status === 401) { // 先刷新令牌 await refreshTokenFn(); // 调用复用函数重试请求 res = await sendAcceptRequest(enemyid); // 重试成功的处理 if (res.status === 200) { toast("Working"); } else { // 重试仍失败的兜底提示 toast("请求失败,请稍后重试或重新登录"); } } } catch (err) { if (err instanceof Error) toast(err.message); setPending(false); } };
这种方式改动最小,只需要把重复的请求逻辑抽离一次,后续要修改请求URL、参数或者请求头,只需要改sendAcceptRequest这一处即可。
方案2:封装通用请求包装器(适合全局多请求复用)
如果你的项目里有大量请求都需要处理401刷新令牌并重试的逻辑,更推荐封装一个通用的请求工具函数,把401的重试逻辑统一封装进去,所有请求都能复用这套逻辑:
// 通用请求包装器,内置401刷新+重试逻辑 const fetchWithAuthRetry = async (fetchParams, allowRetry = true) => { try { const res = await fetch(fetchParams.url, fetchParams.config); // 遇到401且允许重试时,执行刷新令牌+重试 if (res.status === 401 && allowRetry) { await refreshTokenFn(); // 重试时关闭重试开关,避免无限循环(比如刷新令牌后仍返回401的场景) return fetchWithAuthRetry(fetchParams, false); } return res; } catch (err) { throw err; // 抛出错误让调用方自行处理 } }; // 使用通用包装器实现acceptRequest const acceptRequest = async () => { try { const requestParams = { url: `${process.env.NEXT_PUBLIC_SOCKET_SERVER_URL}/acceptRequest`, config: { method: "POST", body: JSON.stringify({ id: enemyid }), credentials: "include", headers: { "Content-Type": "application/json", }, }, }; const res = await fetchWithAuthRetry(requestParams); if (res.status === 200) { toast("Working"); } else if (res.status === 401) { // 重试后仍401,说明刷新令牌失败,提示用户重新登录 toast("登录已过期,请重新登录"); } } catch (err) { if (err instanceof Error) toast(err.message); setPending(false); } };
这个方案的优势是一次封装,全局复用,不管是POST、GET还是其他类型的请求,只要传入对应的URL和配置,就能自动处理401的重试逻辑。同时通过allowRetry开关避免了无限重试的风险。
额外注意事项
- 刷新令牌失败的处理:记得在
refreshTokenFn里处理刷新失败的场景(比如返回401),避免静默失败; - 重试次数限制:如果需要更严谨的控制,可以给通用包装器加重试次数上限,比如最多重试1次;
- 请求防抖/节流:如果是用户频繁触发的请求,可以考虑加防抖,避免短时间内多次刷新令牌。
内容来源于stack exchange
相关产品推荐
相关产品推荐

