React中JWT刷新Token失败处理:避免未捕获错误
解决React JWT应用中Refresh Token失败后无错误跳转登录页的问题
问题根源
你遇到的核心问题是:即使执行了登录跳转,拦截器最后仍会执行return Promise.reject(err),导致上层组件的错误捕获机制(比如React ErrorBoundary)触发,显示未捕获错误页面。此外,多请求同时触发401时会重复调用刷新接口,也会引发额外错误。
修改方案
通过添加刷新锁、终止错误传递两个关键调整,实现无错误跳转:
import axios from "axios"; import TokenService from "./token"; const instance = axios.create({ baseURL: process.env.REACT_APP_BACKEND_API_URL, headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', }, timeout: 5000 }); // 新增:标记是否正在刷新Token,防止多请求重复触发刷新 let isRefreshing = false; instance.interceptors.request.use( (config) => { const token = TokenService.getLocalAccessToken(); if (token) { config.headers['Authorization'] = 'Bearer ' + token; } return config; }, (error) => { return Promise.reject(error); } ); instance.interceptors.response.use( (res) => { return res; }, async (err) => { const originalConfig = err.config; if (originalConfig.url !== "/login" && err.response) { if (err.response.status === 401 && !originalConfig.retry) { // 已有请求在刷新Token时,等待后重试当前请求 if (isRefreshing) { try { await new Promise(resolve => setTimeout(resolve, 500)); return instance(originalConfig); } catch (e) { return Promise.reject(e); } } originalConfig.retry = true; isRefreshing = true; try { const response = await instance.post("/refreshtoken", { "@ObjectType": "RefreshToken#1.0.0", RefreshToken: TokenService.getLocalRefreshToken(), }); TokenService.updateLocalAccessToken(response.data.Token); TokenService.updateLocalRefreshToken(response.data.RefreshToken); isRefreshing = false; return instance(originalConfig); } catch (error) { isRefreshing = false; TokenService.removeUser(); window.location.replace(`${process.env.REACT_APP_FRONTEND_URL}/#/login`); // 关键:返回已resolved的Promise,终止错误传递,避免上层捕获错误 return Promise.resolve(); } } } // 非401刷新失败场景,正常抛出错误 return Promise.reject(err); } ); export default instance;
关键修改说明
- 刷新锁
isRefreshing:避免多个请求同时触发Refresh Token接口,防止重复请求和状态冲突。 - catch块返回
Promise.resolve():终止错误链,上层组件不会捕获到错误,也就不会触发未捕获错误页面。 - 等待重试逻辑:当已有请求在刷新Token时,其他请求等待短暂时间后重试,确保能使用新Token继续请求。
内容的提问来源于stack exchange,提问作者VIPPER
相关产品推荐
相关产品推荐

