使用Spring Data REST,为什么@Version属性成为ETag并且不包含在表示中?

时间:2022-09-11 16:48:50

In Spring Data REST (via Spring Boot 1.3.3), when I GET a resource collection of, say, people, the @Version property is not included with the resources:

在Spring Data REST(通过Spring Boot 1.3.3)中,当我获取人员的资源集合时,@ Version属性不包含在资源中:

$curl -v http://localhost:8080/api/people/1*   Trying ::1...* Connected to localhost (::1) port 8080 (#0)> GET /api/people/1 HTTP/1.1> Host: localhost:8080> User-Agent: curl/7.42.1> Accept: */*> < HTTP/1.1 200 OK< Server: Apache-Coyote/1.1< ETag: "0"< Last-Modified: Tue, 26 Apr 2016 00:08:12 GMT< Content-Type: application/hal+json;charset=UTF-8< Transfer-Encoding: chunked< Date: Tue, 26 Apr 2016 00:12:56 GMT< {  "id" : 1,  "createdDate" : {    "nano" : 351000000,    "epochSecond" : 1461629292  },  "lastModifiedDate" : {    "nano" : 351000000,    "epochSecond" : 1461629292  },  "firstName" : "Bilbo",  "lastName" : "Baggins",  "_links" : {    "self" : {      "href" : "http://localhost:8080/api/people/1"    },    "person" : {      "href" : "http://localhost:8080/api/people/1"    }  }* Connection #0 to host localhost left intact

by default, or when I configure my Spring Data repository:

默认情况下,或者在配置Spring Data存储库时:

@Configurationpublic class ApplicationRepositoryConfiguration     extends RepositoryRestMvcConfiguration {        @Override    protected void configureRepositoryRestConfiguration(        RepositoryRestConfiguration config        )     {        config.exposeIdsFor(Person.class);        config.setBasePath("/api/");    }}

The @Version is the version of the row of data which is incremented on updates, and included in the ETag HTTP Header data when I query a specific resource. Instead of having to invoke a GET on each resource in the collection, I'd prefer getting the @Version in the collection GET so I can write my application to check the @Version value on each resource update without performing the n addition GET round-trips.

@Version是数据行的版本,在更新时递增,并在查询特定资源时包含在ETag HTTP Header数据中。我不想在集合中的每个资源上调用GET,而是更喜欢在集合GET中获取@Version,这样我就可以编写我的应用程序来检查每个资源更新的@Version值,而不执行n加法GET循环 - 旅行。

Is there a way to include the @Version field in each of the resources a collection GET?

有没有办法在集合GET的每个资源中包含@Version字段?

The entity definition looks like this:

实体定义如下所示:

@Data @Entity @EntityListeners(AuditingEntityListener.class)public class Person {    @Id    @GeneratedValue(strategy = GenerationType.AUTO)    private long id;    @CreatedDate    @Column(nullable=false)    private Instant createdDate;    @LastModifiedDate    @Column(nullable=false)    private Instant lastModifiedDate;    @Version    @JsonProperty    private Long version;    …}

1 个解决方案

#1


13  

No, there is not. The ETag is the HTTP equivalent to what's expressed as @Value property in the backend. Spring Data REST turns all backend related properties that have a corresponding mechanism in the HTTP protocol into exactly those: ids become URIs (and shouldn't be part of the payload either), @LastModifiedDate properties become headers, @Version properties, become ETags.

不,那里没有。 ETag是HTTP等同于后端中表示为@Value属性的HTTP。 Spring Data REST将所有在HTTP协议中具有相应机制的后端相关属性转换为:ids成为URI(也不应成为有效负载的一部分),@ LastModifiedDate属性成为标题,@ Version属性成为ETag。

The reason is pretty simple: if you use HTTP, use the protocol means that are available to you to achieve things that are implemented on the data access level. That's one aspect in which Spring Data REST is not simply exposing a database to the web but actually inspects your model and translates model characteristics into protocol specific means.

原因很简单:如果您使用HTTP,请使用可用的协议方法来实现在数据访问级别上实现的内容。这是Spring Data REST不仅仅是将数据库暴露给Web而是实际检查模型并将模型特征转换为协议特定方法的一个方面。

Long story short: with Spring Data REST you have two options for updates:

简而言之:使用Spring Data REST,您有两种更新选项:

  1. Just PUT without an If-Match header — enforces overriding whatever is present on the server as the aggregate gets loaded, incoming data mapped onto it and it written back. You still get optimistic locking applied if another client changed the aggregate in the meantime (although an admittedly very short window). If that's the case you'll see a 409 Conflict.
  2. 只是没有If-Match标头的PUT - 强制覆盖服务器上存在的任何内容,因为聚合被加载,传入的数据映射到它并且它被写回。如果另一个客户端在此期间更改了聚合(尽管这是一个非常短的窗口),您仍然可以应用乐观锁定。如果是这种情况,你会看到409冲突。
  3. PUT with an If-Match header - Spring Data REST checks the ETag submitted against the current value of the version property of the aggregate and return a 412 Precondition Failed in case there's a mismatch at that point. In that case clients can lookup the current state of the resource and decide how to proceed. They might just decide to override what's on the server using PUT without an If-Match header.
  4. 使用If-Match标头进行PUT - Spring Data REST根据聚合的version属性的当前值检查提交的ETag,并在该点出现不匹配的情况下返回412 Precondition Failed。在这种情况下,客户端可以查找资源的当前状态并决定如何继续。他们可能只是决定在没有If-Match标头的情况下使用PUT覆盖服务器上的内容。

Similar optimizations can made for GET requests:

可以对GET请求进行类似的优化:

  1. GET with If-None-Match (ETag) / If-Modified-Since (with Last-Modified header value) — You'll see a 304 Not Modified in case the resource is still in the same state as before and you thus avoid spending bandwidth for the response.
  2. 使用If-None-Match(ETag)/ If-Modified-Since获取(使用Last-Modified标头值) - 如果资源仍处于与之前相同的状态,您将看到304 Not Modified,从而避免花费响应带宽。
  3. Plain GET will always return the representation.
  4. 普通GET将始终返回表示。

#1


13  

No, there is not. The ETag is the HTTP equivalent to what's expressed as @Value property in the backend. Spring Data REST turns all backend related properties that have a corresponding mechanism in the HTTP protocol into exactly those: ids become URIs (and shouldn't be part of the payload either), @LastModifiedDate properties become headers, @Version properties, become ETags.

不,那里没有。 ETag是HTTP等同于后端中表示为@Value属性的HTTP。 Spring Data REST将所有在HTTP协议中具有相应机制的后端相关属性转换为:ids成为URI(也不应成为有效负载的一部分),@ LastModifiedDate属性成为标题,@ Version属性成为ETag。

The reason is pretty simple: if you use HTTP, use the protocol means that are available to you to achieve things that are implemented on the data access level. That's one aspect in which Spring Data REST is not simply exposing a database to the web but actually inspects your model and translates model characteristics into protocol specific means.

原因很简单:如果您使用HTTP,请使用可用的协议方法来实现在数据访问级别上实现的内容。这是Spring Data REST不仅仅是将数据库暴露给Web而是实际检查模型并将模型特征转换为协议特定方法的一个方面。

Long story short: with Spring Data REST you have two options for updates:

简而言之:使用Spring Data REST,您有两种更新选项:

  1. Just PUT without an If-Match header — enforces overriding whatever is present on the server as the aggregate gets loaded, incoming data mapped onto it and it written back. You still get optimistic locking applied if another client changed the aggregate in the meantime (although an admittedly very short window). If that's the case you'll see a 409 Conflict.
  2. 只是没有If-Match标头的PUT - 强制覆盖服务器上存在的任何内容,因为聚合被加载,传入的数据映射到它并且它被写回。如果另一个客户端在此期间更改了聚合(尽管这是一个非常短的窗口),您仍然可以应用乐观锁定。如果是这种情况,你会看到409冲突。
  3. PUT with an If-Match header - Spring Data REST checks the ETag submitted against the current value of the version property of the aggregate and return a 412 Precondition Failed in case there's a mismatch at that point. In that case clients can lookup the current state of the resource and decide how to proceed. They might just decide to override what's on the server using PUT without an If-Match header.
  4. 使用If-Match标头进行PUT - Spring Data REST根据聚合的version属性的当前值检查提交的ETag,并在该点出现不匹配的情况下返回412 Precondition Failed。在这种情况下,客户端可以查找资源的当前状态并决定如何继续。他们可能只是决定在没有If-Match标头的情况下使用PUT覆盖服务器上的内容。

Similar optimizations can made for GET requests:

可以对GET请求进行类似的优化:

  1. GET with If-None-Match (ETag) / If-Modified-Since (with Last-Modified header value) — You'll see a 304 Not Modified in case the resource is still in the same state as before and you thus avoid spending bandwidth for the response.
  2. 使用If-None-Match(ETag)/ If-Modified-Since获取(使用Last-Modified标头值) - 如果资源仍处于与之前相同的状态,您将看到304 Not Modified,从而避免花费响应带宽。
  3. Plain GET will always return the representation.
  4. 普通GET将始终返回表示。