此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Data REST 4.5.3! |
带标头的条件作
本节展示 Spring Data REST 如何使用标准 HTTP 标头来增强性能、条件化作以及为更复杂的前端做出贡献。
ETag
,If-Match
和If-None-Match
头
这ETag
页眉提供了一种标记资源的方法。这可以防止客户端相互覆盖,同时还可以减少不必要的调用。
请考虑以下示例:
class Sample {
@Version Long version; (1)
Sample(Long version) {
this.version = version;
}
}
1 | 这@Version 注释(如果您使用的是 Spring Data JPA,则为 JPA,Spring Dataorg.springframework.data.annotation.Version 所有其他模块的一个)将此字段标记为版本标记。 |
前面示例中的 POJO 在由 Spring Data REST 作为 REST 资源提供时,具有ETag
header 替换为 version 字段的值。
我们可以有条件地PUT
,PATCH
或DELETE
如果我们提供If-Match
标头,如下所示:
curl -v -X PATCH -H 'If-Match: <value of previous ETag>' ...
仅当资源的当前ETag
state 匹配If-Match
标头是执行的作。此保护措施可防止客户端相互STOMP踏。两个不同的客户端可以获取资源并具有相同的资源ETag
. 如果一个客户端更新资源,它会获得一个新的ETag
在响应中。但第一个客户端仍然具有旧标头。如果该客户端尝试使用If-Match
标头,则更新失败,因为它们不再匹配。相反,该客户端会收到 HTTP412 Precondition Failed
要发回的消息。然后客户端可以赶上,但这是必要的。
术语“版本”可能带有不同的语义,具有不同的数据存储,甚至是应用程序中的不同语义。Spring Data REST 有效地委托给数据存储的元模型,以辨别字段是否经过版本控制,如果是,则仅允许在以下情况下列出的更新ETag 元素匹配。 |
这If-None-Match
页眉提供了替代方案。而不是条件更新,If-None-Match
允许条件查询。请考虑以下示例:
curl -v -H 'If-None-Match: <value of previous etag>' ...
前面的命令(默认情况下)运行一个GET
. Spring Data REST 检查If-None-Match
headers 同时执行GET
. 如果标头与 ETag 匹配,则它得出结论,没有任何更改,并且不会发送资源的副本,而是发回 HTTP304 Not Modified
状态代码。从语义上讲,它显示为“如果此提供的标头值与服务器端版本不匹配,请发送整个资源。否则,不要发送任何内容。
这个 POJO 来自一个ETag -基于单元测试,因此它没有@Entity (JPA) 或@Document (MongoDB) 注释,正如应用程序代码中所预期的那样。它仅关注具有@Version 结果为ETag 页眉。 |
If-Modified-Since
页眉
这If-Modified-Since
页眉提供了一种检查资源自上次请求以来是否已更新的方法,这使应用程序可以避免重新发送相同的数据。请考虑以下示例:
@Document
public class Receipt {
public @Id String id;
public @Version Long version;
public @LastModifiedDate Date date; (1)
public String saleItem;
public BigDecimal amount;
}
1 | Spring Data Commons 的@LastModifiedDate 注释允许以多种格式捕获此信息(JodaTime 的DateTime 、旧版 JavaDate 和Calendar 、JDK8 日期/时间类型和long /Long ). |
对于前面示例中的日期字段,Spring Data REST 返回一个Last-Modified
标头,类似于以下内容:
Last-Modified: Wed, 24 Jun 2015 20:28:15 GMT
可以捕获此值并将其用于后续查询,以避免在未更新时两次提取相同的数据,如以下示例所示:
curl -H "If-Modified-Since: Wed, 24 Jun 2015 20:28:15 GMT" ...
使用上述命令,您要求仅在资源自指定时间以来发生更改时才获取资源。如果是这样,您将获得修订后的Last-Modified
用于更新客户端的标头。如果没有,您将收到一个 HTTP304 Not Modified
状态代码。
标头的格式非常完美,可以发回以供将来查询。
不要将标头值与不同的查询混合和匹配。结果可能是灾难性的。仅当您请求完全相同的 URI 和参数时才使用标头值。 |
构建更高效的前端
ETag
元素,结合If-Match
和If-None-Match
headers,让你构建一个对消费者的数据计划和移动电池寿命更友好的前端。为此,请执行以下作:
-
确定需要锁定的实体并添加版本属性。
HTML5 很好地支持
data-*
属性,因此将版本存储在 DOM 中(例如data-etag
属性)。 -
确定可从跟踪最新更新中受益的条目。获取这些资源时,将
Last-Modified
DOM 中的值 (data-last-modified
也许)。 -
获取资源时,还要嵌入
self
DOM 节点中的 URI(也许是data-uri
或data-self
),以便轻松返回资源。 -
调整
PUT
/PATCH
/DELETE
要使用的作If-Match
并处理 HTTP412 Precondition Failed
状态代码。 -
调整
GET
要使用的作If-None-Match
和If-Modified-Since
并处理 HTTP304 Not Modified
状态代码。
通过嵌入ETag
元素和Last-Modified
值,然后您可以通过不一遍又一遍地检索相同的内容来减少数据和电池电量的消耗。您还可以避免与其他客户端发生冲突,而是在需要协调差异时收到警报。
通过这种方式,只需对前端进行一些调整和一些实体级编辑,后端就会提供时间敏感的详细信息,您可以在构建客户友好的客户端时从中获利。