4.3.5. Freshening Responses via HEAD

1 阅读4分钟

4.3.5. Freshening Responses via HEAD

rfc 4.3.5. Freshening Responses via HEAD

HEAD只能用于刷新GET方法

TODO 目前没有找到明确的反对证据

用途

A response to the HEAD method is identical to what an equivalent
   request made with a GET would have been, except it lacks a body.
   This property of HEAD responses can be used to invalidate or update a
   cached GET response if the more efficient conditional GET request
   mechanism is not available (due to no validators being present in the
   stored response) or if transmission of the representation body is not
   desired even if it has changed.

"update"指的是:更新(SHOULD)GET的stored response的:header+warning。

"invalidate"指的是:将GET的stored response标记为(SHOULD)stale。

HEAD可以用于在如下2种情况时执行 前面定义的 "invalidate/update"操作:

  • 没有Validators时
  • 执行"invalidate/update"但是避免body传输时。

假设使用GET+If-None-Match+Etag发起请求:

  • 304表示没有变化(Etag matched),会返回4.1. 304 Not Modified规定的Header,并且不会返回body
  • 200表示有变化(Etag not match),会返回GET方法执行结果,其中包含body

显然,当返回200时会涉及body的传输,"if it has changed"指的就是这种情况。

"invalidate/update"条件

基本条件

为given request target发起一个HEAD请求,收到了200 response。然后假设为given request target发起GET请求"selected"请求,计算"select" 的GET responses(the cache SHOULD update or invalidate each of its stored GET responses that could have been selected for that request)

"update"条件

对比"selected" response和HEAD response,如果:

  • ETag match
  • Last-Modified match
  • Content-Length match

如果上述所有条件满足则执行(SHOULD)"update",否则就执行(SHOULD)"invalidate"。

为什么只对比ETag match不行?

在实际情况中,可能会出现相同Etag但是不同representation的情况。下面举一些例子:

1.弱Etag:

rfc没有禁止HEAD请求过程中使用强还是弱Etag,当cache收到一个弱Etag时,没法确定对应的representation是否变化。

2.忽略传输编码: 假设服务器开发者自己写了一段逻辑:ETag = hash(file_content)。

  • 用户 A 请求 style.css,服务器发现其支持 Gzip,于是压缩并返回。
  • 用户 B 请求 style.css,服务器发现其支持 Brotli,于是压缩并返回。

结果

  • 两个响应的 ETag 都是基于“原始文件内容”算出来的,所以完全相同。但由于压缩算法不同,实际传输的字节(Representation)完全不同

3.基于“修改时间 + 文件大小”的启发式算法

很多老旧的 Web 服务器(如早期的 Apache 或自定义的 File Server)为了节省 CPU,不扫描文件内容,而是用: ETag = 文件的 Last-Modified + 文件大小 (Size)。

假设下列操作都发生在1s以内:

  • HEAD请1求到来,
  • 修改文件内容,但是文件大小没变
  • HEAD请2求到来

结果

虽然内容发生了变化,但是由于操作发生在1s以内,Last-Modified是秒,文件大小也没变,所以2次返回同一个Etag。

这三个操作的意图是?

进行"update"之前,执行这3个match是为了验证“representation大概率没变”(例如前面的文件修改的例子,虽然3个match都满足,但是representation还是变了), 而不是为了验证“representation100%没变”。

"invalidate"条件

"update"条件不满足时执行"invalidate"

update具体操作

  o  delete any Warning header fields in the stored response with
      warn-code 1xx (see Section 5.5);

   o  retain any Warning header fields in the stored response with
      warn-code 2xx; and,

   o  use other header fields provided in the HEAD response to replace
      all instances of the corresponding header fields in the stored
      response and append new header fields to the stored response's
      header section unless otherwise restricted by the Cache-Control
      header field.

主要解释一下第三个操作:

  • 相同Header,替换
  • 新的Header,apend
  • 保留stored response中有,HEAD response中没有的Header(这是gemini说的)
  • 用Cache-Control header field约束上面3条规则

“restricted by the Cache-Control header field”

假设现在收到一个满足“update”条件的HEAD response 200

no-store

HTTP/1.1 200 OK
Date: Mon, 12 Oct 2023 11:00:00 GMT
ETag: "v1-abc"
Content-Length: 1024
Cache-Control: no-store  <-- 这里的指令就是一种 "restriction"

restricted:

由于no-store的存在,cache不能更新stored response中的Header,还必须(MUST)把对应的stored response给删了。

容易误解:no-cache=value

HTTP/1.1 200 OK
Date: Mon, 12 Oct 2023 11:00:00 GMT
ETag: "v1-abc"
Cache-Control: no-cache="Set-Cookie" <-- 限制 Set-Cookie 字段被存储
Set-Cookie: ID=xyz123; HttpOnly

注意,rfc中只规定了:cache在将no-cache=value给client使用之前必须先去origin server验证;并没有规定no-cache指定的Header不能被存储。 所以,no-cache不会restricted HEAD请求收到response以后的"update"操作。

容易误解:no-cache

HTTP/1.1 200 OK
Date: Mon, 12 Oct 2023 11:00:00 GMT
ETag: "v1-abc"
Cache-Control: no-cache
Set-Cookie: ID=xyz123; HttpOnly

分析同上,这种情况也没有restricted产生。