通过拦截器在 fetch 返回的 promise 链中处理响应,先提取原始数据,再使用 crypto.subtle 进行验签,验证通过后才将数据传递给后续逻辑。具体做法是封装一个自定义的 requestwithverify 函数,该函数接收请求配置和公钥参数,内部调用 fetch 获取响应后,解析 json 并校验签名字段,若校验失败则抛出异常。

如何封装支持验签的请求函数
封装的核心在于利用 Promise 的链式调用特性,在 fetch 完成网络请求后、业务代码消费数据前插入验签步骤。需要确保服务器返回的数据结构中包含用于验签的 sign 字段和原始数据 data。验签过程需要将原始数据序列化为字符串,并使用 Web Crypto API 的 verify 方法比对签名。如果签名无效,直接 reject 错误,阻止脏数据进入应用层。

const publicKeyPEM = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END PUBLIC KEY-----`;
async function requestWithVerify(url, options = {}, publicKeyPEM) {
const response = await fetch(url, options);
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
const result = await response.json();
if (!result.sign || !result.data) {
throw new Error('Invalid response structure');
}
const isValid = await verifySignature(result.data, result.sign, publicKeyPEM);
if (!isValid) {
throw new Error('Signature verification failed');
}
return result.data;
}
async function verifySignature(data, signatureBase64, publicKeyPEM) {
const algorithm = { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' };
const pubKeyObj = await crypto.subtle.importKey(
'pem', publicKeyPEM, algorithm, false, ['verify']
);
const sigBuffer = Uint8Array.from(atob(signatureBase64), c => c.charCodeAt(0));
const dataStr = typeof data === 'string' ? data : JSON.stringify(data);
const dataBuffer = new TextEncoder().encode(dataStr);
return await crypto.subtle.verify(algorithm, pubKeyObj, sigBuffer, dataBuffer);
}
上述代码展示了完整的实现逻辑。requestWithVerify 函数首先发起标准 fetch 请求,随后解析 JSON 响应体。接着调用 verifySignature 辅助函数,该函数负责将 PEM 格式的公钥导入为 CryptoKey 对象,并将 Base64 编码的签名转换为二进制缓冲区。最后,使用 crypto.subtle.verify 对序列化后的数据进行校验。调用方只需传入 URL、请求选项和公钥即可安全获取数据。
如何处理验签失败与重试机制
当验签失败时,通常意味着数据在传输过程中被篡改或服务器私钥泄露,此时不应简单重试,而应记录日志并终止当前操作。但在某些场景下,如临时网络波动导致签名校验异常(极少见),可设计有限次数的重试逻辑。更常见的情况是,验签失败后需要触发特定的错误处理流程,例如刷新 Token 或通知用户。这里重点讨论如何在封装中优雅地处理这些分支,确保主程序不因单一请求失败而崩溃。

safeRequest
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











