使用 Spring Data REST,为什么 @Version 属性成为 ETag 并且不包含在表示中? [英] With Spring Data REST, why is the @Version property becoming an ETag and not included in the representation?

查看:14
本文介绍了使用 Spring Data REST,为什么 @Version 属性成为 ETag 并且不包含在表示中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Spring Data REST(通过 Spring Boot 1.3.3)中,当我 GET 一个资源集合时,例如 people@Version 属性不包含在资源中:

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:

$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

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

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

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

@Version 是更新时递增的数据行的版本,并包含在 ETag HTTP Header 数据中我查询特定资源.而不是必须在集合中的每个资源上调用 GET,我宁愿在集合 GET 中获取 @Version,这样我就可以编写我的应用程序以检查每次资源更新时的 @Version而不执行 n 添加 GET 往返.

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.

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

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

实体定义如下所示:

@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;

    …
}

推荐答案

不,没有.ETag 是 HTTP 等价物,在后端表示为 @Value 属性.Spring Data REST 将所有在 HTTP 协议中具有相应机制的后端相关属性完全转换为:id 成为 URI(也不应该成为有效负载的一部分),@LastModifiedDate 属性成为标题,@Version 属性,成为 ETags.

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.

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

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.

长话短说:使用 Spring Data REST,您有两个更新选项:

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

  1. 只是 PUT 没有 If-Match 标头 - 强制覆盖服务器上存在的任何内容,因为聚合被加载,传入的数据映射到它并写回.如果同时另一个客户端更改了聚合,您仍然会应用乐观锁定(尽管窗口非常短).如果是这种情况,您将看到 409 冲突.
  2. PUT 带有 If-Match 标头 - Spring Data REST 根据聚合的 version 属性的当前值检查提交的 ETag 并返回 412Precondition Failed 以防万一此时出现不匹配.在这种情况下,客户端可以查找资源的当前状态并决定如何进行.他们可能只是决定使用没有 If-Match 标头的 PUT 覆盖服务器上的内容.
  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. 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.

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

Similar optimizations can made for GET requests:

  1. GETIf-None-Match (ETag)/If-Modified-Since(带有 Last-Modified 标头值)——你'将看到 304 Not Modified 以防资源仍处于与以前相同的状态,从而避免为响应花费带宽.
  2. 普通 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. Plain GET will always return the representation.

这篇关于使用 Spring Data REST,为什么 @Version 属性成为 ETag 并且不包含在表示中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆