通过封装 fetch 函数并拦截响应来实现接口请求结果认证策略。具体做法是在调用 fetch 后检查 http 状态码,若为 401 则触发重新登录或刷新 token 的逻辑,随后重试原请求;若为其他错误则抛出异常。这样可以将认证逻辑从业务代码中剥离,统一处理鉴权失败的情况。

如何封装 fetch 以自动处理 401 未授权
封装 fetch 的核心在于拦截器模式。在发起请求前附加认证头(如 Bearer Token),并在收到响应时判断状态码。如果状态码是 401,说明 Token 过期或无效,此时应执行刷新 Token 的操作,然后使用新的 Token 重试之前的请求。这种机制确保了业务代码无需关心具体的鉴权细节,只需关注数据获取本身。

async function authenticatedFetch(url, options = {}) {
// 1. 获取当前有效的 Token
const token = await getValidToken();
// 2. 构建请求配置,添加 Authorization 头
const fetchOptions = {
...options,
headers: {
...options.headers,
'Authorization': `Bearer ${token}`
}
};
try {
// 3. 发起首次请求
const response = await fetch(url, fetchOptions);
// 4. 检查是否为 401 未授权
if (response.status === 401) {
console.log('Token expired, refreshing...');
// 5. 刷新 Token
await refreshToken();
// 6. 使用新 Token 重试请求
const newToken = await getValidToken();
fetchOptions.headers['Authorization'] = `Bearer ${newToken}`;
return await fetch(url, fetchOptions);
}
// 7. 非 401 错误直接抛出
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
// 8. 成功返回 JSON 数据
return await response.json();
} catch (error) {
console.error('Fetch failed:', error);
throw error;
}
}
// 模拟辅助函数
function getValidToken() { return Promise.resolve('old-token'); }
function refreshToken() { return Promise.resolve('new-token'); }如何处理 Token 刷新期间的并发请求
当多个请求同时遇到 401 时,如果每个请求都独立执行刷新 Token 操作,会导致重复的网络请求和潜在的竞态条件。正确的做法是维护一个刷新锁(Lock)或队列。当第一个请求发现 Token 过期时,它负责发起刷新请求,并将后续的请求挂起,直到刷新完成。刷新完成后,通知所有挂起的请求使用新 Token 重试。这样可以保证同一时间只有一个刷新动作发生,提高效率和稳定性。
你是 TypeScript 项目架构专家,专注于脚手架搭建生产就绪的 Node.js 和前端应用。生成包含现代工具链(pnpm、Vite、Next.js)、类型
立即学习“Java免费学习笔记(深入)”;

let isRefreshing = false;
let refreshSubscribers = [];
function subscribeTokenRefresh(cb) {
refreshSubscribers.push(cb);
}
function onRefreshed(newToken) {
refreshSubscribers.forEach(cb => cb(newToken));
refreshSubscribers = [];
}
async function robustAuthenticatedFetch(url, options = {}) {
let token = await getValidToken();
const fetchOptions = {
...options,
headers: { ...options.headers, 'Authorization': `Bearer ${token}` }
};
try {
let response = await fetch(url, fetchOptions);
if (response.status === 401) {
if (!isRefreshing) {
isRefreshing = true;
try {
await refreshToken();
const newToken = await getValidToken();
onRefreshed(newToken);
} finally {
isRefreshing = false;
}
}
// 等待刷新完成并获取新 Token
const newToken = await new Promise(resolve => {
subscribeTokenRefresh(resolve);
});
fetchOptions.headers['Authorization'] = `Bearer ${newToken}`;
response = await fetch(url, fetchOptions);
}
if (!response.ok) throw new Error(`Status: ${response.status}`);
return await response.json();
} catch (error) {
throw error;
}
}基于程序中某个输入、条件或结果的具体问题
在上述代码中,如果 refreshToken() 本身也失败了(例如网络断开或服务器完全不可用),程序会进入什么状态?根据代码逻辑,refreshToken() 的异常会被捕获吗?在当前实现中,如果 refreshToken() 抛出异常,isRefreshing 标志会在 finally 块中被重置为 false,但 onRefreshed 不会被调用,导致 subscribeTokenRefresh 中的 Promise 永远挂起。这会造成后续所有依赖该 Token 的请求无限期阻塞。因此,需要在刷新失败时明确拒绝所有订阅者,而不是让他们无限等待。

















