如何封装通用Fetch函数统一处理JWT认证与401重定向?
通用Fetch封装方案
当然可以通过封装通用Fetch函数来统一处理状态码检查、401重定向以及token自动刷新逻辑,避免每个请求重复写相同的判断代码。以下是适配你服务端JWT认证逻辑的实现方案:
封装通用Fetch函数
// 可将该函数放在独立工具文件中,比如src/utils/api.js let accessToken = localStorage.getItem('accessToken') || ''; const apiFetch = async (url, options = {}) => { // 统一设置请求头,携带当前有效accessToken const headers = { 'Content-Type': 'application/json', ...options.headers, ...(accessToken && { Authorization: accessToken }) }; const config = { ...options, headers, credentials: 'include' // 确保请求携带cookie(refreshToken存储在cookie中) }; let response = await fetch(url, config); // 处理401未授权状态 if (response.status === 401) { // 调用刷新token接口尝试获取新的accessToken const refreshResponse = await fetch('/api/refresh-token', { method: 'POST', credentials: 'include' }); if (refreshResponse.ok) { const newToken = refreshResponse.headers.get('Authorization'); await refreshResponse.json(); // 更新本地存储的accessToken accessToken = newToken; localStorage.setItem('accessToken', newToken); // 用新token重新发起原请求 config.headers.Authorization = newToken; response = await fetch(url, config); } else { // refreshToken也失效,直接重定向到登录页 window.location.href = '/login'; return Promise.reject(new Error('登录已过期,请重新登录')); } } // 统一处理非成功状态码 if (!response.ok) { const errorData = await response.json().catch(() => ({ message: '请求失败' })); return Promise.reject(new Error(errorData.message || `请求错误:${response.status}`)); } return response.json(); };
关键逻辑说明
- 全局token管理:用变量
accessToken维护当前有效令牌,更新后所有后续请求会自动使用新token - 自动重试机制:遇到401时自动调用刷新token接口,获取新token后重新发起原请求,对业务代码完全透明
- 统一错误捕获:所有非2xx状态码都会被封装为错误抛出,业务代码只需通过
try/catch处理异常 - 凭证携带:设置
credentials: 'include'确保请求携带cookie,让服务端能读取到refreshToken
业务代码中使用
直接用封装好的apiFetch替换原生fetch,无需再手动处理401:
// 原写法 // const res = await fetch('/api/user'); // const d = await res.json(); // if(res.status === 401) { redirect('/login') } // 新写法 try { const userData = await apiFetch('/api/user'); // 处理业务数据 } catch (error) { // 处理其他错误(如网络异常、服务器500等) console.error(error.message); }
服务端适配建议
你现有的authenticate中间件可以拆分出单独的刷新token接口,方便客户端调用:
// 新增refresh-token接口 app.post('/api/refresh-token', (req, res) => { const refreshToken = req.cookies['refreshToken']; if (!refreshToken) { return res.status(401).send('No refresh token provided.'); } try { const decoded = jwt.verify(refreshToken, secretKey); const newAccessToken = jwt.sign({ user: decoded.user }, secretKey, { expiresIn: '1h' }); res .cookie('refreshToken', refreshToken, { httpOnly: true, sameSite: 'strict' }) .header('Authorization', newAccessToken) .json(decoded.user); } catch (error) { return res.status(400).send('Invalid refresh token.'); } });
这样就实现了请求逻辑的统一处理,无需在每个请求中重复编写401判断和重定向代码。
内容的提问来源于stack exchange,提问作者wepro01
相关产品推荐
相关产品推荐

