在现代的单页应用(SPA)中,用户认证是一个至关重要的部分。为了保护用户的信息安全,通常会使用JWT(JSON Web Token)进行身份验证。然而,Token通常有一定的有效期,在有效期到期后,用户需要重新登录以获取新Token,这可能会影响用户体验。为了解决这个问题,我们可以实现Token的无感刷新机制,允许用户在不知觉中自动更新Token。
第一步:设置Axios实例
我们将使用Axios创建一个实例,并设置请求和响应拦截器。确保你已经安装了Axios:
npm install axios
然后创建一个 axiosInstance.js文件:
import axios from 'axios'; const axiosInstance = axios.create({ baseURL: 'https://api.example.com', // 替换为你的 API 地址 }); // 添加请求拦截器 axiosInstance.interceptors.request.use(config => { const token = localStorage.getItem('token'); // 从存储中获取当前的 Token if (token) { config.headers['Authorization'] = `Bearer ${token}`; // 将 Token 加入请求头 } return config; }, error => { return Promise.reject(error); });
第二步:添加响应拦截器
我们需要处理401错误(即未授权)并尝试刷新Token。在响应拦截器中,我们监控请求的状态,如果遇到Token过期的情况,则发起刷新Token的请求。
let isRefreshing = false; let pendingRequests = []; axiosInstance.interceptors.response.use(response => { return response; }, async error => { const originalRequest = error.config; // 检查是否是401错误以及是否已经在刷新Token if (error.response.status === 401 && !isRefreshing) { isRefreshing = true; try { const refreshToken = localStorage.getItem('refreshToken'); // 获取 Refresh Token const response = await axios.post('/auth/refresh', { token: refreshToken }); // 刷新 Token 的请求 const { token } = response.data; // 假设新的 Token 在这里返回 localStorage.setItem('token', token); // 保存新 Token // 重试原始请求 pendingRequests.forEach(callback => callback(token)); pendingRequests = []; return axiosInstance(originalRequest); // 重发原始请求 } catch (err) { // 如果刷新失败,清除 Token 并重定向到登录页面等 localStorage.removeItem('token'); localStorage.removeItem('refreshToken'); window.location.href = '/login'; // 跳转到登录页 return Promise.reject(err); } finally { isRefreshing = false; } } // 如果正在刷新Token,将后续请求加入队列 if (isRefreshing) { return new Promise((resolve, reject) => { pendingRequests.push((token) => { originalRequest.headers['Authorization'] = `Bearer ${token}`; resolve(axiosInstance(originalRequest)); }); }); } return Promise.reject(error); });
第三步:用户登录与登出
当用户登录成功时,我们需要保存Token和Refresh Token。以下是一个简单的登录函数示例:
async function login(username, password) { const response = await axios.post('/auth/login', { username, password }); const { token, refreshToken } = response.data; // 假设返回数据中包含 Token 和 Refresh Token localStorage.setItem('token', token); localStorage.setItem('refreshToken', refreshToken); }
用户登出时,我们需要清理存储的 Token:
function logout() { localStorage.removeItem('token'); localStorage.removeItem('refreshToken'); window.location.href = '/login'; // 跳转到登录页 }
第四步:使用Axios实例
最后,在你的组件或服务中使用配置好的Axios实例进行API请求。
axiosInstance.get('/some-protected-route') .then(response => { console.log(response.data); }) .catch(error => { console.error(error); });