Web 服务器如何确定 ETag 值是否是最新的?

How does a web server determine if an ETag value is current?

示例场景

假设 /some-view 有一个资源显示基于数据库查询的列表,例如

客户端 X 向 /some-view 发出第一个请求,服务器处理响应、缓存它、生成一个 etag,然后用 200 将其发回。

一段时间过去了,/some-view 的列表中包含另一个项目

假设客户端 X 再次发送第一个请求,服务器是否会以 304 响应直到另一个请求,例如客户端 Y,强制生成新的 etag 值,还是服务器实际处理响应并将其与当前 etag 进行比较以确定它是否仍然有效?也许不同的网络服务器处理方式不同?

如果响应是动态生成的,服务器实际上必须生成它才能生成 ETag 并将其与请求进行比较。如果它们匹配,那么服务器可以避免发送响应,但它无法避免首先生成它,至少在 ETag 只是响应的哈希的一般情况下(例如,ETag 过滤器)不会.当然,ETag 可以是任何东西,所以在一般情况下,服务器必须生成响应,如果您制作自己的 ETag,您可以在其中包含一些信息,您的服务器可以使用这些信息来确定它是否可以 return 304 而不必生成响应。

ETag 有两种场景:静态资源(文件)的 ETag,以及动态查询结果的 ETag(如问题所述)。

如果“web服务器”指的是Apache或Nginx等服务器软件,则它只为静态资源提供ETag特性,对于动态结果不会自动生成或更新ETag。例如,根据 Nginx document:

Syntax: etag on | off;

Default: etag on;

Enables or disables automatic generation of the “ETag” response header field for static resources.

原因是:web服务器软件可以监听文件变化,更新ETag,但是永远无法判断数据库中的一堆数据是否被修改。

如果“web server”表示服务器端逻辑,您可以自己生成和管理 ETag(例如 URL 及其对应的 ETag 的映射)。 RFC7232 的唯一要求是:

An origin server SHOULD send an ETag for any selected representation for which detection of changes can be reasonably and consistently determined

因此,这里的重点是“检测变化”——您可以选择最合适的解决方案:

  • 监听write-resource操作,并更新ETag。
  • 每 5 分钟在后台查询一次资源,并在发生更改时更新 ETag。
  • 问题中描述的“客户端 Y”解决方案。
  • 问题中描述的“处理和比较”解决方案。
  • 更多...

只要解决方案能够合理、一致地检测到变化,就是一个好的解决方案。