参见:https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching#Freshness
当缓存收到对过时资源的请求时,它会使用 If-None-Match 转发此请求,以检查它实际上是否仍然是最新的。如果是这样,服务器将返回 304(未修改(标头,而不发送所请求资源的正文,从而节省一些带宽。
假设我们有:浏览器缓存、代理缓存和源服务器:
- 浏览器缓存包含带有实体标记"A"的存储过时资源。
- 代理缓存包含带有实体标记"B"的存储过时资源。代理缓存可以充当客户端和服务器。
例如,如果您刚刚开始使用代理缓存,则可能出现这种情况。在这种情况下会发生什么?
- 浏览器将发送一个条件请求,其中包含 If-None-Match:"A"。
- 代理缓存接收条件请求。
- 代理缓存将转发此请求(根据上面的引用(。这是因为代理缓存中存储的资源已过时。
- 源服务器接收带有实体标记"A"的请求。
假设源服务器上的资源包含实体标记"A"。现在,服务器将以"304 未修改"响应进行响应。
在这一点上,我已经不明白了,所以也许我以前误解了什么?304 响应对于浏览器缓存是可以的,因为它包含与源服务器上相同的资源(相同的实体标记(。但是,代理缓存包含较旧的资源(具有不同的 Etag(。如果代理缓存将收到 304 响应(并更新其元数据(,则代理缓存会使资源在旧资源时再次有效。
这是不可取的,所以可能是我在某处犯了一个错误?它实际上是如何工作的?我必须如何看待这个过程?
请看RFC7234规范的第 4.3 节。 第 4.3.2 节特别指出以下内容:
当缓存决定重新验证其自己存储的响应时 包含实体标记的"如果无匹配"列表的请求,即缓存 可以将收到的列表与其自身的实体标签列表组合在一起 存储的响应集(新鲜或过时(并发送 两个列表作为替换 If-None-Match 标头字段值 转发的请求。 如果存储的响应仅包含部分 内容,缓存不得在联合中包含其实体标记 除非请求的范围可以完全满足 该部分存储响应。 如果响应转发 请求为 304(未修改(,并且具有 ETag 标头字段值 不在客户端列表中的实体标记,缓存必须 通过重用其 相应的存储响应,由 304 响应更新 元数据(第 4.3.4 节(。
因此,代理可以将两个实体标记(A 和 B(发送到源服务器进行验证。如果资源表示形式未更改,则源服务器将发送304
响应。如果该响应中的实体标记B
,则代理可以刷新其过时的存储响应,并使用它来向客户端发送200 OK
响应。收到此新响应后,浏览器可以使用它更新其缓存。
现在,在您指定的方案中,304 NOT MODIFIED
响应包含实体标记A
(假设您通过代理访问资源,这种情况甚至会发生吗?该规范似乎没有明确解决这种特定情况,但我想您可以将304 NOT MODIFIED
响应转发到浏览器。收到它后,浏览器可以使用其元数据刷新过时的响应。