fetch 本身无内置拦截器,但可通过封装 request 函数实现请求前自动注入 token、响应后捕获 401 并刷新重试;需配合防并发刷新(如 refreshingpromise)及 token 状态同步,模拟拦截器效果。

Fetch 本身没有内置拦截器机制,但可以通过封装请求函数、结合 Promise 链和状态管理(如全局 token 存储),在发起请求前自动注入 Token,并在收到 401 响应时触发刷新逻辑,再重试原请求。核心在于“拦截发送前”和“拦截响应后”的手动控制,而非类似 Axios 的中间件式拦截器。
封装 fetch 请求,统一添加 Authorization 头
所有请求走一个自定义的 request() 函数,在里面读取当前 token 并附加到 headers:
async function request(url, options = {}) {
const token = getToken(); // 从 localStorage / 内存 / 状态管理中获取
const headers = {
'Content-Type': 'application/json',
...options.headers,
};
if (token) {
headers.Authorization = `Bearer ${token}`;
}
return fetch(url, {
...options,
headers,
});
}
响应拦截:捕获 401 并自动刷新 Token 后重试
在 request 函数内部处理响应结果,若返回 401,则调用刷新接口,更新本地 token,再用新 token 重发原请求(注意避免无限循环):
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
async function request(url, options = {}) {
const token = getToken();
const headers = {
'Content-Type': 'application/json',
...options.headers,
};
if (token) headers.Authorization = `Bearer ${token}`;
const res = await fetch(url, { ...options, headers });
// 成功直接返回
if (res.ok) return res;
// 401 触发刷新流程
if (res.status === 401) {
try {
const newToken = await refreshAccessToken();
setToken(newToken); // 持久化新 token
// 重试原请求(注意:需排除 headers 中旧 Authorization,或确保新 token 已生效)
return request(url, options); // 递归重试(简单场景可用)
} catch (refreshErr) {
// 刷新失败,清空 token 并跳转登录页
clearToken();
window.location.href = '/login';
throw refreshErr;
}
}
throw new Error(`HTTP error! status: ${res.status}`);
}
防并发刷新:避免多个 401 请求同时触发多次刷新
当多个请求几乎同时返回 401,需确保只执行一次刷新,其余等待同一 promise 结果:
- 用一个变量(如 refreshingPromise)缓存正在执行的刷新 promise
- 后续 401 请求不再发起新刷新,而是 await 这个已有 promise
- 刷新成功后重置该变量,下次 401 才会重新发起刷新
可选增强:支持取消重复请求或配置重试次数
实际项目中可进一步加限制,例如:
- 对非幂等请求(如 POST/PUT)不自动重试,仅对 GET 安全重试
- 设置最大重试次数(如 1 次),防止死循环
- 使用 AbortController 控制原请求取消(刷新期间可 cancel 旧请求)
不复杂但容易忽略的是 token 状态同步和并发控制——只要把 token 获取、刷新、存储、错误跳转这几环串起来,并加一层防重逻辑,就能模拟出接近拦截器的效果。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










