在 javascript 中实现 fetch api 的请求数据预鉴权,核心做法是在发起请求前拦截并修改 request 对象或配置项,将鉴权所需的 token、签名或加密参数注入到 url 查询字符串、header 或 body 中。具体而言,可以封装一个自定义的 fetchwithauth 函数,该函数接收原始配置,通过异步方法获取最新凭证(如从 localstorage 读取或调用刷新接口),然后构造新的 requestinit 对象覆盖原有参数,最后调用原生 fetch 发送请求。这样做能确保所有出站请求都携带有效的鉴权信息,且逻辑集中管理,避免在每个业务模块重复编写鉴权代码。

如何拦截并注入 Header 鉴权令牌
拦截并注入 Header 鉴权令牌的做法是创建一个包装函数,在调用 fetch 之前检查当前会话状态,并将 Authorization 字段添加到 headers 对象中。如果本地存储了 JWT 或 Access Token,直接读取并设置;若 Token 过期,可在此处触发刷新逻辑。此方法适用于大多数 RESTful API 调用,因为服务端通常通过 Header 验证身份。关键在于处理并发请求时 Token 刷新的竞态条件,以及确保未认证请求被正确拒绝或重定向。

// fetchWithAuth.js
const TOKEN_KEY = 'auth_token';
async function fetchWithAuth(url, options = {}) {
const token = localStorage.getItem(TOKEN_KEY);
if (!token) {
throw new Error('No authentication token found');
}
// 合并默认 headers 和自定义 headers
const headers = {
...options.headers,
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
};
const fetchOptions = {
...options,
headers
};
try {
const response = await fetch(url, fetchOptions);
// 处理 401 Unauthorized
if (response.status === 401) {
// 这里可以触发刷新 Token 的逻辑
throw new Error('Token expired or invalid');
}
return response;
} catch (error) {
console.error('Fetch error:', error);
throw error;
}
}
// 使用示例
fetchWithAuth('/api/user/profile', { method: 'GET' })
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
上述代码展示了基本的 Header 注入流程。首先从 localStorage 获取 auth_token,若不存在则抛出错误。接着构建包含 Authorization 头的 headers 对象,并与传入的 options 合并。调用 fetch 后,检查响应状态码,若为 401 则表明凭证失效,需进一步处理。这种模式简单有效,适用于大多数需要 Bearer Token 的场景。
如何在 POST 请求体中预计算签名参数
对于要求请求体签名的 API,预鉴权策略需要在发送前对 Body 数据进行哈希计算,并将签名值作为额外字段加入 JSON 对象或表单数据中。具体做法是序列化原始 Body,使用 HMAC-SHA256 等算法生成签名,然后将签名附加到 Payload 中,再重新序列化为字符串传递给 fetch。这种方法常用于高安全性要求的金融或政务接口,防止中间人篡改请求内容。需注意签名算法需与后端一致,且 Secret Key 应安全存储。

// fetchWithSignature.js
const crypto = require('crypto');
const SECRET_KEY = 'your_secret_key_here';
function generateSignature(payloadString, secretKey) {
return crypto.createHmac('sha256', secretKey)
.update(payloadString)
.digest('hex');
}
async function fetchWithSignature(url, options = {}) {
let bodyData = options.body;
// 如果是 JSON 对象,先序列化
if (typeof bodyData === 'object' && !Buffer.isBuffer(bodyData)) {
bodyData = JSON.stringify(bodyData);
}
// 生成签名
const signature = generateSignature(bodyData, SECRET_KEY);
// 解析回对象以添加签名字段
let parsedBody = typeof bodyData === 'string' ? JSON.parse(bodyData) : bodyData;
parsedBody.signature = signature;
parsedBody.timestamp = Date.now();
// 重新序列化
const finalBody = JSON.stringify(parsedBody);
const fetchOptions = {
...options,
body: finalBody,
headers: {
...options.headers,
'Content-Type': 'application/json'
}
};
return fetch(url, fetchOptions);
}
// 使用示例
fetchWithSignature('/api/secure/transfer', {
method: 'POST',
body: {
amount: 100,
recipient: 'user123'
}
})
.then(res => res.json())
.then(data => console.log(data));
该代码演示了如何在 POST 请求体中嵌入签名。首先定义 generateSignature 函数,使用 Node.js 的 crypto 模块进行 HMAC-SHA256 计算。在 fetchWithSignature 中,若传入的是对象,则先序列化为字符串以便计算签名。计算完成后,将签名和时间戳添加回解析后的对象,再重新序列化为最终 Body。这种方式确保了请求内容的完整性和真实性,但增加了客户端的计算开销,需权衡性能与安全需求。
当 Token 刷新失败时如何处理并发请求
当 Token 刷新失败时,处理并发请求的关键是维护一个刷新队列,将所有因 401 错误触发的请求挂起,直到刷新完成或失败。具体做法是使用 Promise 链或 async/await 机制,在检测到 401 时不立即重试,而是等待刷新操作完成。若刷新成功,则用新 Token 重试所有挂起的请求;若刷新失败,则统一拒绝这些请求并跳转登录页。这避免了无限循环刷新和重复请求,保证系统稳定性。
// fetchWithQueue.js
let isRefreshing = false;
let refreshSubscribers = [];
function subscribeTokenRefresh(cb) {
refreshSubscribers.push(cb);
}
function onRefreshed(newToken) {
refreshSubscribers.forEach(cb => cb(newToken));
refreshSubscribers = [];
}
async function refreshToken() {
if (isRefreshing) return null;
isRefreshing = true;
try {
// 模拟刷新 Token 的 API 调用
const response = await fetch('/api/auth/refresh', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token: localStorage.getItem('refresh_token') })
});
const data = await response.json();
localStorage.setItem('auth_token', data.access_token);
onRefreshed(data.access_token);
return data.access_token;
} catch (error) {
// 刷新失败,清空队列并重定向
refreshSubscribers = [];
window.location.href = '/login';
return null;
} finally {
isRefreshing = false;
}
}
async function fetchWithQueue(url, options = {}) {
const token = localStorage.getItem('auth_token');
try {
const response = await fetch(url, {
...options,
headers: { ...options.headers, 'Authorization': `Bearer ${token}` }
});
if (response.status === 401) {
if (!isRefreshing) {
await refreshToken();
}
// 重试原请求
const newToken = localStorage.getItem('auth_token');
return fetch(url, {
...options,
headers: { ...options.headers, 'Authorization': `Bearer ${newToken}` }
});
}
return response;
} catch (error) {
throw error;
}
}
此代码实现了基于订阅者模式的 Token 刷新队列。全局变量 isRefreshing 标记刷新状态,refreshSubscribers 数组存储待处理的回调函数。当多个请求同时收到 401 时,第一个请求触发刷新,后续请求通过 subscribeTokenRefresh 注册回调并等待。刷新成功后,onRefreshed 通知所有订阅者,他们可使用新 Token 重试请求。若刷新失败,则清空队列并引导用户登录。这种机制有效解决了并发场景下的鉴权问题,提升了用户体验和系统健壮性。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











