响应头中的 ETag 值是如何生成的

要求

  • 当文件不会更改时,ETAG 值保持不变。
  • 计算速度快,耗费CPU资源少
  • 便于扩展,多个服务器上此资源生成的 ETAG 值要相同。

nginx 中 ETag 的生成

Content-Length: 612
Last-Modified: Tue, 23 Apr 2019 10:18:21 GMT
ETag: "5cbee66d-264"

计算规则

new Date(parseInt('5cbee66d', 16) * 1000).toJSON()
"2019-04-23T10:18:21.000Z"
> parseInt('264', 16)
612

express 采用 etag 库生成

静态资源一般都只是生成的长度-时间戳而已,

动态接口可以配置,可以算hash。

app.set('etag', true); // weak ETag,长度-时间戳
app.set('etag', 'strong'); // strong ETag, hash
app.set('etag', function (body, encoding) {
  return generateHash(body, encoding); // consider the function is defined
});

核心代码详细见这里,截取一小段:

function etag (entity, options) {
  // ...
  // generate entity tag
  var tag = isStats
    ? stattag(entity)
    : entitytag(entity)

  // ...
}

function entitytag (entity) {
  if (entity.length === 0) {
    // fast-path empty
    return '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"'
  }

  // compute hash of entity
  var hash = crypto
    .createHash('sha1')
    .update(entity, 'utf8')
    .digest('base64')
    .substring(0, 27)

  // compute length of entity
  var len = typeof entity === 'string'
    ? Buffer.byteLength(entity, 'utf8')
    : entity.length

  return '"' + len.toString(16) + '-' + hash + '"'
}
function stattag (stat) {
  var mtime = stat.mtime.getTime().toString(16)
  var size = stat.size.toString(16)

  return '"' + size + '-' + mtime + '"'
}

真实线上静态资源文件的Etag。

ETag: "713-1551786316000"
Last-Modified: Tue, 05 Mar 2019 11:45:16 GMT


ETag: "SAdqG/HfsklgQeEc+r/SZg=="
Last-Modified: Thu, 16 Jan 2020 06:17:05 GMT

而 koa 的 etag 插件底层还是 express 的 etag。

posted @ 2020-04-26 15:13  Ever-Lose  阅读(3037)  评论(0编辑  收藏  举报