Angular:双Token场景下HTTP请求前Token校验方案咨询
解决页面内API请求前的Token过期校验问题
这问题我之前在项目里也碰到过——路由守卫只能管页面跳转的场景,页面内的异步API请求确实覆盖不到。最靠谱的方案就是给你的HTTP客户端(比如Axios、Fetch)加请求拦截器,让它在每次发请求前自动完成Token校验和刷新逻辑,完美补全路由守卫的盲区。下面给你拆解具体实现步骤:
1. 先封装一个Token过期校验工具函数
首先需要一个通用函数来判断token_b是否过期,建议提前几秒判定过期(比如30秒),避免网络延迟导致请求到达后端时刚好过期:
function isTokenExpired(token) { if (!token) return true; // 没有Token直接判定为过期 try { // 解析JWT的Payload部分(注意:仅前端校验,后端仍会做最终校验) const payload = JSON.parse(atob(token.split('.')[1])); const expireTime = payload.exp * 1000 - 30000; // 提前30秒过期 return Date.now() > expireTime; } catch (err) { // 解析失败(比如Token格式错误)也判定为过期 return true; } }
2. 给HTTP客户端添加请求拦截器
以常用的Axios为例,通过拦截器在请求发出前统一处理Token逻辑,还能解决并发请求重复刷新Token的问题:
import axios from 'axios'; // 创建Axios实例 const apiClient = axios.create({ baseURL: '/your-api-base-url' }); // 刷新Token的Promise锁:避免多个并发请求同时触发刷新 let refreshTokenPromise = null; // 请求拦截器 apiClient.interceptors.request.use(async (config) => { let tokenB = localStorage.getItem('token_b'); const tokenA = localStorage.getItem('token_a'); // 检查token_b是否过期 if (isTokenExpired(tokenB)) { // 如果没有正在进行的刷新请求,发起刷新 if (!refreshTokenPromise) { refreshTokenPromise = apiClient.post('/refresh-token', { token_a: tokenA }) .then(res => { const newTokenB = res.data.token_b; localStorage.setItem('token_b', newTokenB); return newTokenB; }) .catch(err => { // 刷新失败:说明token_a也失效了,跳转到登录页并清空Token localStorage.removeItem('token_a'); localStorage.removeItem('token_b'); window.location.href = '/login'; return Promise.reject(err); }) .finally(() => { // 刷新完成后释放锁 refreshTokenPromise = null; }); } // 等待刷新完成,获取新的token_b tokenB = await refreshTokenPromise; } // 将有效的token_b添加到请求头 if (tokenB) { config.headers.Authorization = `Bearer ${tokenB}`; } return config; }, (error) => { return Promise.reject(error); });
3. 如果用Fetch的替代方案
如果项目用原生Fetch,可以封装一个带Token校验的请求函数,所有API请求都通过这个函数发起:
async function fetchWithToken(url, options = {}) { let tokenB = localStorage.getItem('token_b'); const tokenA = localStorage.getItem('token_a'); if (isTokenExpired(tokenB)) { // 发起Token刷新请求 const refreshRes = await fetch('/refresh-token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ token_a: tokenA }) }); if (!refreshRes.ok) { // 刷新失败,跳登录页 localStorage.removeItem('token_a'); localStorage.removeItem('token_b'); window.location.href = '/login'; throw new Error('Token refresh failed'); } const refreshData = await refreshRes.json(); tokenB = refreshData.token_b; localStorage.setItem('token_b', tokenB); } // 给请求添加Token头 options.headers = { ...options.headers, Authorization: `Bearer ${tokenB}` }; return fetch(url, options); }
方案优势
这种方式能覆盖所有HTTP请求场景:不管是页面内的异步API调用,还是路由跳转触发的请求,都会自动经过Token校验和刷新逻辑,和路由守卫形成互补,完全不需要在每个请求里手动写校验代码。
内容的提问来源于stack exchange,提问作者Kay
相关产品推荐
相关产品推荐

