首页 > 解决方案 > 我可以将 E-tag 用于用户特定的 REST API,以免每次都发回相同的数据吗?

问题描述

假设我们有一个检索用户特定数据的 API。出于某种原因,我不希望服务器每次都将数据发送回客户端,因为数据没有变化。

例如,我有一个移动应用程序。每次启动时,它都会显示来自本地缓存的数据,但也会在后台从服务器检索一些特定于用户的数据。我想要做的是希望服务器可以在数据不变的情况下返回 304。

似乎 E-tag 可以做这种事情,但我不确定它是否是一个好的选择,因为它是一个用户特定的 API。

标签: apiresthttpetaghttp-status-code-304

解决方案


HTTP 是一种请求/响应协议。对于客户端发送的每个请求,服务器都会响应。响应可以是失败也可以是成功案例。除非出现网络中断,否则绝不应该出现服务器不响应的情况!

特别是 ETag 通常是资源当前状态的哈希值或预定义的字符串值,即版本计数器(正如 Evert 正确提到的),在响应中作为 HTTP 标头返回,因此客户端可以在想要更改的情况下使用它该特定状态并且不希望服务器在该资源同时被修改时更新它(=乐观锁定)。

使用 ETag 的第二种情况是检查客户端的状态是否仍然是服务器已知的当前状态,服务器根据资源是否仍然具有相同的 ETag 值来响应 a304 Not Modified412 Precondition failed响应。理想情况下,您应该向服务器发出 HEAD 请求,以最小化来回发送的有效负载,因为您可能感兴趣的是客户端已知的当前版本是否仍然是服务器持有的版本。

...但我不确定这是否是一个不错的选择,因为它是一个用户特定的 API。

...我阅读了一些关于 E-tag 的文章,但它们都没有提到任何关于用户特定数据的内容。...

正如Jim Webber所指出的,从本质上讲,HTTP 只是一种传输协议,其域是通过 Web 传输文档。您最好将其视为文档管理系统,您可以将新文件放在某个位置,删除或检索它们或根据服务器自己的语义通过POST要求。HTTP 基本上就是这样。因此,任何遵守 HTTP 规则的 HTTP 客户端都能够使用 RFC 7232 中指定的条件请求,HTTP 服务器也应该如此。因此,数据来自某个 HTTP Web 服务器还是来自某个 Java、.Net 或任何中间件或框架支持的 API 没有区别,只要它们遵循相同的 HTTP 协议即可。不幸的是,如果你愿意的话,一个特定的框架或实现是否支持那种“特性”是另一回事。

关于使用条件请求是否是一个不错的选择,您有哪些选择?如果客户端想知道它是否具有资源的最新状态,它要么需要礼貌地询问服务器客户端知道的版本是否仍然是最新版本,要么只需检索整个状态(再次)。有些人可能会争辩说,在版本因其他客户端的中间更新而不同的情况下,需要交换多条消息。这是一个有效的论点,尽管您需要估计哪些可能会更频繁地发生。在客户端很少检查其版本是否仍然是最新版本或各种客户端频繁更新该资源的情况下,可能再次检索该资源的整个状态可能会减少总共交换的字节数,因此最终会更有效率。虽然 HTTP 提供HEAD您可以利用这些请求来最小化客户端和服务器之间交换的有效负载大小,如 HTTP 定义HEAD的那样

...服务器不得在响应中发送消息正文(即响应在标头部分的末尾终止)。服务器应该发送相同的头字段来响应 HEAD 请求,因为如果请求是 GET 则它会发送,除了可以省略有效负载头字段(第 3.3 节)。此方法可用于获取有关所选表示的元数据,而无需传输表示数据...

HEAD 请求消息中的有效负载没有定义的语义;在 HEAD 请求上发送有效负载主体可能会导致某些现有实现拒绝该请求。(资源)

本质上,HEAD对此类请求的请求和响应仅包含 HTTP 标头,而没有进一步的消息正文,这有助于显着降低交换消息的字节大小。在最好的情况下,当两个版本相同时,您显着减少了交换的字节数。在最坏的情况下,如果它们不同,那么额外的开销可能可以忽略不计,除非你真的在一个高性能的边缘笼子里。因此,如果您对您当前对某些资源的了解是否仍然是最新的知识感兴趣,则通过条件请求HEAD是一个不错的选择 IMO。


推荐阅读