使用数据库主键构造 http ETag headers 是个坏主意吗?

Is it a bad idea to construct http ETag headers using database primary keys?

我可以使用数据库密钥(来自不可变 object)作为 ETag 吗?

我正在尝试让浏览器 and/or 代理缓存为我的 Web 应用程序工作(恰好是 python/flask,但我认为这不是特别相关)。在我读到的有关 ETag 的所有内容中,它们通常被讨论为(可能是静态的)资源的哈希值。

就我而言,我的数据库中有 class 个 object 不可编辑。这些 object 中的每一个都可以生成几个不同的视图。生成视图,至少其中一些视图,需要在服务器上进行一些工作,但通常生成的输出是轻量级的。因此,先生成整个页面,然后再进行哈希运算,效率会很低,我也可以在那个时候发送响应。

我的想法是,因为每个视图都建立在一个不可变的数据库object上,所以object的键(加上请求的URL)就足以知道是否客户端的缓存好坏。但这意味着对许多不同的资源使用相同的 ETag。据我所知,这似乎应该可行,但是

更多上下文

我的应用程序具有 URL 的形式:

example.com/view/<name>/<version>/<view>/<additional view args>

DB 在 <name><version> 的组合上有唯一索引。但是对于版本有一个特殊的关键字latest,它会导致服务器找到带有<name>的最新条目。无论请求什么视图,它都完全由名称和版本找到的 object 定义。因此,如果客户端发送带有 If-none-match: <key> 的请求 header,我将始终 return 304 而不管请求的视图,除非 (a) 他们请求 latest 版本并且 (b)数据库中最新版本的主键与 If-none-match header.

不匹配

我建议阅读 RFC 7232,它非常简单明了,可以让您很好地理解条件验证。

您希望在知道是否存在匹配之前避免计算响应是明智且允许的。正如标准所明确的那样,选择不透明值取决于您。哈希只是其中的一个特例。 (实际上,它们需要特别提及,因为理论上可能会发生冲突。)该标准特别给出了 the example 使用 ETag 的版本号:

For example, a resource that has implementation-specific versioning applied to all changes might use an internal revision number, perhaps combined with a variance identifier for content negotiation, to accurately differentiate between representations.

您还询问是否每个资源的 ETag 都需要不同。 answer 不是:

There is no implication of uniqueness across representations of different resources (i.e., the same strong validator might be in use for representations of multiple resources at the same time and does not imply that those representations are equivalent).

有些人会担心将数据库 ID 暴露给客户端。我对此没有强烈的感觉,但当然可以通过散列或以其他方式隐藏 ID 轻松避免这种情况。

不过,看看您的具体设计,似乎只需为您的 ETag 使用 version 就足够了。事实上,对于 latest 以外的所有资源,似乎只有一种可能的表示形式。如果是这样,您应该将这些条目设置为永远缓存,而 ETag 是什么并不重要。然后对于 latest 使用较短的缓存时间并使用 version (或主键,如果您愿意)作为 ETag。