核心思路是请求前预判token过期:每次发请求前校验access_token剩余有效期,若低于阈值(如60秒)则调用刷新接口更新token,再用新token发起原请求。

Token过期检测与自动刷新逻辑
核心思路是:每次发起请求前,检查当前 Token 是否即将过期(比如剩余有效期
用 Promise 链实现无感刷新调度
不能让多个并发请求各自去刷新 Token,否则会发多次刷新请求。需用一个 pendingRefreshPromise 缓存正在刷新的 Promise,后续请求都复用它:
- 首次检测到需刷新时,调用
refreshToken()并把返回的 Promise 存入缓存 - 后续请求发现缓存存在且未 settle,就直接
await它,共享结果 - 刷新成功后,更新本地 Token 和过期时间;失败则清空缓存并跳转登录
封装成可复用的请求拦截器函数
以 Axios 为例,可在请求拦截器中返回一个 Promise:
let pendingRefresh = null;
<p>function getValidToken() {
const token = localStorage.getItem('token');
const expiresAt = +localStorage.getItem('expiresAt') || 0;
const isNearExpiry = Date.now() + 30_000 > expiresAt; // 提前30秒刷新
const isExpired = Date.now() >= expiresAt;</p><p>if (isExpired && !pendingRefresh) {
pendingRefresh = refreshTokenApi().then(res => {
localStorage.setItem('token', res.token);
localStorage.setItem('expiresAt', String(Date.now() + res.expiresIn * 1000));
return res.token;
}).catch(() => {
localStorage.removeItem('token');
localStorage.removeItem('expiresAt');
pendingRefresh = null;
window.location.href = '/login';
throw new Error('Token refresh failed');
});
}</p><p>if (isNearExpiry && pendingRefresh) {
return pendingRefresh;
}</p><p>return Promise.resolve(token);
}</p><p>// 请求拦截器
axios.interceptors.request.use(config => {
if (config.url.includes('/api/') && !config.skipAuth) {
return getValidToken().then(token => {
config.headers.Authorization = <code>Bearer ${token}</code>;
return config;
});
}
return config;
});</p>避免死循环和重复刷新的关键细节
刷新接口本身不能走鉴权,否则会无限递归。务必给刷新请求加 skipAuth: true 标记,并在拦截器中跳过 Token 注入;同时刷新成功后要重置 pendingRefresh 为 null(上面示例已在 catch 中处理,但 resolve 后也应重置);另外建议在 refreshTokenApi 内部用独立的 axios 实例,彻底隔离拦截器逻辑。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











