对于最新的稳定版本,请使用 Spring Data REST 4.4.0spring-doc.cadn.net.cn

带标头的条件作

本节介绍 Spring Data REST 如何使用标准 HTTP 标头来提高性能、条件化作并为更复杂的前端做出贡献。spring-doc.cadn.net.cn

ETag,If-MatchIf-None-Match

ETag页眉提供了一种标记资源的方法。这可以防止客户端相互覆盖,同时还可以减少不必要的调用。spring-doc.cadn.net.cn

请考虑以下示例:spring-doc.cadn.net.cn

示例 1.具有版本号的 POJO
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标头替换为 version 字段的值。spring-doc.cadn.net.cn

我们可以有条件地PUT,PATCHDELETE该资源(如果我们提供If-Match标头,例如:spring-doc.cadn.net.cn

curl -v -X PATCH -H 'If-Match: <value of previous ETag>' ...

仅当资源的当前ETagstate 与If-Matchheader 是执行的作。这种保护措施可以防止客户端相互STOMP踏。两个不同的客户端可以获取资源,并且具有相同的ETag.如果一个客户端更新资源,它会获得一个新的ETag在响应中。但是第一个客户端仍然具有旧的标头。如果该客户端尝试使用If-Match标头,则更新会失败,因为它们不再匹配。相反,该客户端会收到一个 HTTP412 Precondition Failed要发回的消息。然后,客户可以赶上,但这是必要的。spring-doc.cadn.net.cn

术语“版本”可能具有不同的语义,具有不同的数据存储,甚至在您的应用程序中具有不同的语义。Spring Data REST 有效地委托给数据存储的元模型,以识别字段是否进行了版本控制,如果是,则只允许列出的更新,如果ETag元素匹配。

If-None-Match页眉提供了另一种选择。而不是条件更新,If-None-Match允许条件查询。请考虑以下示例:spring-doc.cadn.net.cn

curl -v -H 'If-None-Match: <value of previous etag>' ...

前面的命令(默认情况下)运行GET.Spring Data REST 检查If-None-Matchheaders 执行GET.如果标头与 ETag 匹配,则它会得出结论,没有任何更改,并且不会发送资源的副本,而是发回 HTTP304 Not Modified状态代码。从语义上讲,它显示为“如果此提供的标头值与服务器端版本不匹配,请发送整个资源。否则,不要发送任何东西。spring-doc.cadn.net.cn

这个 POJO 来自ETag-基于单元测试,因此它没有@Entity(JPA) 或@Document(MongoDB) 注释,如应用程序代码中所预期的那样。它只关注具有@Version结果为ETag页眉。

If-Modified-Since页眉

If-Modified-Since页眉提供一种方法来检查资源自上次请求以来是否已更新,从而使应用程序避免重新发送相同的数据。请考虑以下示例:spring-doc.cadn.net.cn

示例 2.在域类型中捕获的上次修改日期
@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 的@LastModifiedDateannotation 允许以多种格式捕获此信息(JodaTime 的DateTime、旧版 JavaDateCalendar、JDK8 日期/时间类型以及long/Long).

对于前面示例中的日期字段,Spring Data REST 返回一个Last-Modified标头,类似于以下内容:spring-doc.cadn.net.cn

Last-Modified: Wed, 24 Jun 2015 20:28:15 GMT

可以捕获此值并将其用于后续查询,以避免在未更新时两次获取相同的数据,如下例所示:spring-doc.cadn.net.cn

curl -H "If-Modified-Since: Wed, 24 Jun 2015 20:28:15 GMT" ...

使用上述命令,您要求仅在资源自指定时间以来发生更改时才获取资源。如果是这样,您将获得修订后的Last-Modified标头。如果没有,您将收到一个 HTTP304 Not Modified状态代码。spring-doc.cadn.net.cn

标头的格式完美,可以发回以供将来查询。spring-doc.cadn.net.cn

不要将标头值与不同的查询混合和匹配。结果可能是灾难性的。仅在请求完全相同的 URI 和参数时使用标头值。

构建更高效的前端

ETag元素与If-MatchIf-None-Matchheaders,让您构建一个对消费者的数据计划和移动电池寿命更友好的前端。为此,请执行以下作:spring-doc.cadn.net.cn

  1. 确定需要锁定的实体并添加 version 属性。spring-doc.cadn.net.cn

    HTML5 很好地支持data-*属性,因此将版本存储在 DOM 中(例如data-etag属性)。spring-doc.cadn.net.cn

  2. 确定将从跟踪最新更新中受益的条目。在获取这些资源时,将Last-Modified值 (data-last-modified也许)。spring-doc.cadn.net.cn

  3. 在获取资源时,还要嵌入selfURI(可能是data-uridata-self),以便轻松返回到资源。spring-doc.cadn.net.cn

  4. 调整PUT/PATCH/DELETE要使用的作If-Match并且还处理 HTTP412 Precondition Failed状态代码。spring-doc.cadn.net.cn

  5. 调整GET要使用的作If-None-MatchIf-Modified-Since并处理 HTTP304 Not Modified状态代码。spring-doc.cadn.net.cn

通过嵌入ETag元素和Last-Modified值(或者可能是本机移动应用程序的其他位置)中,然后您可以通过不一遍又一遍地检索相同的内容来减少数据和电池电量的消耗。您还可以避免与其他客户端发生冲突,而是在需要协调差异时收到提醒。spring-doc.cadn.net.cn

以这种方式,只需对前端进行一些调整和一些实体级编辑,后端就可以提供时效性细节,您可以在构建客户友好型客户端时获利。spring-doc.cadn.net.cn