使用 fetch api 实现请求数据预签名,核心做法是在发起 http 请求前,先通过后端接口获取包含时间戳、随机数(nonce)和签名字符串的 token,随后在请求的 header 或 query string 中携带这些参数。具体而言,你需要调用一个专门的签名生成接口,拿到结果后将其拼接到 fetch 调用的 headers 对象中,这样服务端就能验证请求的合法性和时效性。

如何获取并组装预签名所需的 Header 参数
获取预签名参数的第一步是向服务器请求签名凭证,通常这是一个独立的 API 端点。拿到返回的 JSON 数据后,需要提取其中的 key、timestamp 和 signature 字段,并将它们放入 fetch 请求的 headers 中。服务端通常会校验 timestamp 与当前时间的差值,以及根据 key 和 body 计算出的 signature 是否匹配,以此防止重放攻击和数据篡改。

async function fetchWithSignature(url, options = {}) {
// 1. 获取签名凭证
const signResponse = await fetch('/api/sign');
const { key, timestamp, signature } = await signResponse.json();
// 2. 构建请求头
const headers = {
...options.headers,
'X-API-Key': key,
'X-Timestamp': timestamp,
'X-Signature': signature
};
// 3. 发起带签名的请求
return fetch(url, {
...options,
headers
});
}如何处理签名失败或过期的情况
当签名过期或无效时,服务端通常会返回 401 或 403 错误。此时前端代码应当捕获该异常,重新触发签名获取流程,并使用新的签名重试原请求。这种重试机制确保了在网络波动或签名短暂失效时,用户操作不会直接中断,而是自动恢复。需要注意的是,为了避免无限重试循环,应限制最大重试次数。
立即学习“Java免费学习笔记(深入)”;

async function safeFetch(url, options = {}, retries = 3) {
try {
const signResponse = await fetch('/api/sign');
const { key, timestamp, signature } = await signResponse.json();
const response = await fetch(url, {
...options,
headers: {
...options.headers,
'X-API-Key': key,
'X-Timestamp': timestamp,
'X-Signature': signature
}
});
if (!response.ok) throw new Error('Request failed');
return response;
} catch (error) {
if (retries > 0 && error.message.includes('Signature')) {
console.log('Retrying with new signature...');
return safeFetch(url, options, retries - 1);
}
throw error;
}
}基于 X-Timestamp 字段的具体问题
在预签名机制中,X-Timestamp 字段用于验证请求的新鲜度。如果客户端时间与服务器时间偏差过大,服务端会拒绝请求。因此,开发者必须确保客户端获取的时间戳是准确的,或者在服务端允许一定的时间窗口(如 ±5 分钟)。在实际编码中,直接使用 Date.now() 生成的毫秒级时间戳是最常见的做法,因为它精度足够且易于处理。


















