后会无期之 jshttp 解析(二):ETag 生成原理
2023-09-15 15:47:22
我们昨天解读了 fresh 这个库,了解了服务器是如何对比文件是否更新了,其中用到了 ETag,那么今天我们就趁热打铁,了解下 ETag 是怎么生成的,同样是来自 jshttp 的 ETag 库。也就是说,资源发生改变的时候,ETag 的值一定发生了改变,那么 ETag 又是如何生成的呢?
内容变化,当然离不开算 Hash 值,但是 ETag 生成并非直接对内容计算 Hash 值,而是对内容的 Buffer 对象计算 Hash 值。对此我们先来了解下 Buffer 对象。
Buffer 对象
Buffer 对象是 Node.js 中处理二进制数据的对象。它是一个类似于数组的对象,可以通过索引来访问二进制数据,但与数组不同,Buffer 对象中的元素都是无符号 8 位整数。也就是说,Buffer 对象可以被看作一个字节数组,其中每个元素的值在 0 到 255 之间。
创建 Buffer 对象有以下几种方式:
- 通过
Buffer.from(data)
创建:data
可以是字符串、ArrayBuffer、Array、Buffer 等。 - 通过
Buffer.alloc(size)
创建:创建一个指定大小的 Buffer 对象,填充为 0。 - 通过
Buffer.allocUnsafe(size)
创建:创建一个指定大小的 Buffer 对象,不进行初始化。
ETag 生成
ETag 的生成就是对 Buffer 对象计算 Hash 值,jshttp 库使用的是 `crypto` 模块中的 `createHash()` 函数。`createHash()` 函数接受一个算法参数,指定要使用的哈希算法,默认值为 "sha1",即 SHA-1 算法。
ETag 生成的代码如下:
export function generate(buf: Buffer, weak?: boolean): string {
// 弱 ETag,一般用于代理服务器
if (weak) {
return `W/"${createHash(buf).toString("base64")}"`;
}
// 强 ETag
return `"${createHash(buf).toString("base64")}"`;
}
function createHash(buf: Buffer) {
return crypto.createHash("sha1").update(buf).digest();
}
以上代码中,`createHash()` 函数创建了一个 SHA-1 哈希对象,然后调用 `update()` 函数更新哈希对象,并将 Buffer 对象作为参数传递。最后,调用 `digest()` 函数获取哈希值,并使用 Base64 编码转换成字符串。
生成的 ETag 是一个用双引号包裹的 Base64 编码字符串,如果指定了 `weak` 参数,则会在 ETag 前面添加一个 "W/" 前缀,表示这是一个弱 ETag。
至此,我们就了解了 ETag 是如何生成的,在下一篇文章中,我们将继续探讨 ETag 的使用场景和相关应用。