1. 程式人生 > >你知道 http 響應頭中的 ETag 是如何生成的嗎

你知道 http 響應頭中的 ETag 是如何生成的嗎

關於 etag 的生成需要滿足幾個條件

  1. 當檔案不會更改時,etag 值保持不變。所以不能單純使用 inode
  2. 便於計算,不會特別耗 CPU。這樣子 hash 不是特別合適
  3. 便於橫向擴充套件,多個 node 上生成的 etag 值一致。這樣子 inode 就排除了

關於伺服器中 etag 如何生成可以參考 HTTP: Generating ETag Header

那麼在 nginx 中的 etag 是如何生成的?

nginx 中 ETag 的生成

我在網上找到一些資料與原始碼瞭解到了 etag 的計算方法。由 python 偽程式碼表示計算方法如下

etag = '{:x}-{:x}'.format(header.last_modified, header.content_lenth)

原始碼: ngx_http_core_modules.c

etag->value.len = ngx_sprintf(etag->value.data, "\"%xT-%xO\"",
                                  r->headers_out.last_modified_time,
                                  r->headers_out.content_length_n)
                      - etag->value.data;

總結:nginxetag

由響應頭的 Last-ModifiedContent-Length 表示為十六進位制組合而成。

隨手在我的k8s叢集裡找個 nginx 服務測試一下

$ curl --head 10.97.109.49
HTTP/1.1 200 OK
Server: nginx/1.16.0
Date: Tue, 10 Dec 2019 06:45:24 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 23 Apr 2019 10:18:21 GMT
Connection: keep-alive
ETag: "5cbee66d-264"
Accept-Ranges: bytes

etag 計算 Last-ModifiedContent-Length,使用 js 計算如下,結果相符

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

Last-Modified,ETag 與協商快取

我們知道協商快取有兩種方式

  • Last-Modified/if-Modified-Since
  • ETag/If-None-Match

既然在 nginxETagLast-ModifiedContent-Length 組成,那它便算是一個加強版的 Last-Modified 了,那加強在什麼地方呢?

** Last-Modified 是由一個 unix timestamp 表示,則意味著它只能作用於秒級的改變**

那下一個問題:如果 http 響應頭中 ETag 值改變了,是否意味著檔案內容一定已經更