PromiseKit:实现认证API 401时刷新令牌并重试的方案求助
解决方案:带自动令牌刷新的API请求封装
我来给你提供一个实用的实现方案,以JavaScript为例,核心是通过Promise机制封装请求逻辑,自动处理401状态下的令牌刷新与请求重试,同时避免并发场景下的重复刷新问题:
核心实现思路
- 封装带认证的基础请求函数,判断响应状态码
- 捕获401未授权状态,触发令牌刷新流程
- 刷新成功后更新令牌,并重试原API请求
- 处理刷新失败的边界情况(比如刷新接口也返回401)
- 加入并发控制,防止多个请求同时触发重复刷新
代码示例
// 全局变量:保存正在进行的刷新请求,避免重复调用刷新接口 let ongoingRefreshPromise = null; // 模拟从本地存储获取当前访问令牌(实际项目可替换为状态管理库读取) const getCurrentAccessToken = () => localStorage.getItem('accessToken'); // 模拟保存新的访问令牌 const saveNewAccessToken = (newToken) => localStorage.setItem('accessToken', newToken); // 刷新令牌的API请求函数 const refreshAuthToken = async () => { // 如果已有正在进行的刷新请求,直接返回这个Promise if (ongoingRefreshPromise) { return ongoingRefreshPromise; } try { ongoingRefreshPromise = fetch('/api/refresh-token', { method: 'POST', // 根据你的接口设计携带刷新凭证,比如refresh token或cookie credentials: 'include' }).then(async (res) => { if (!res.ok) throw new Error('令牌刷新失败'); const { accessToken } = await res.json(); saveNewAccessToken(accessToken); return accessToken; }).finally(() => { // 刷新完成后清空全局Promise,允许下次触发刷新 ongoingRefreshPromise = null; }); return ongoingRefreshPromise; } catch (err) { // 刷新失败时清除本地无效令牌,触发登录逻辑 localStorage.removeItem('accessToken'); throw err; } }; // 带自动重试的认证请求封装 const authRequest = async (url, options = {}) => { const token = getCurrentAccessToken(); const requestOptions = { ...options, headers: { ...options.headers, Authorization: `Bearer ${token}` // 根据你的认证方式调整,比如Basic Auth } }; const response = await fetch(url, requestOptions); // 状态码200-299,直接返回响应数据 if (response.ok) { return response.json(); } // 处理401未授权情况 if (response.status === 401) { try { // 刷新令牌 await refreshAuthToken(); // 刷新成功后,递归调用原请求重试 return authRequest(url, options); } catch (refreshErr) { throw new Error('令牌已失效且刷新失败,请重新登录'); } } // 其他错误状态,直接抛出错误 throw new Error(`请求失败,状态码:${response.status}`); };
关键细节说明
- 并发刷新控制:通过
ongoingRefreshPromise全局变量,确保多个请求同时触发401时,只会发起一次令牌刷新,避免接口重复调用。 - 令牌管理:
getCurrentAccessToken和saveNewAccessToken是抽象的令牌读写函数,你可以根据项目技术栈(比如Vuex、Redux、SessionStorage)替换实现。 - 错误边界处理:刷新令牌失败时,主动清除本地无效令牌并抛出错误,方便上层逻辑(比如全局错误拦截器)处理登出或跳转登录页的操作。
- 重试逻辑:刷新成功后递归调用
authRequest,复用原请求的所有参数,保证重试请求的准确性。
如果你的项目使用Axios等请求库,逻辑是类似的——可以通过请求拦截器注入令牌,响应拦截器捕获401并触发刷新重试,核心逻辑和上面的实现一致。
内容的提问来源于stack exchange,提问作者Luigi Marino
相关产品推荐
相关产品推荐

