加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – 在Spring MVC REST中的ETag处理

发布时间:2020-12-14 05:14:19 所属栏目:Java 来源:网络整理
导读:我正在考虑从Apache CXF RS与JAX RS切换到 Spring MVC REST,并查看Spring MVC REST当前正在处理ETag的方式的一些问题.也许我不明白,还是有更好的方式来实现JAX RS目前正在做的工作? 使用Apache CXF RS,在REST服务中评估最后修改的时间戳和ETag的条件(条件评
我正在考虑从Apache CXF RS与JAX RS切换到 Spring MVC REST,并查看Spring MVC REST当前正在处理ETag的方式的一些问题.也许我不明白,还是有更好的方式来实现JAX RS目前正在做的工作?

使用Apache CXF RS,在REST服务中评估最后修改的时间戳和ETag的条件(条件评估实际上相当复杂,请参见RFC 2616第14.24和14.26节,因此我很高兴为我做).代码看起来像这样:

@GET
@Path("...")
@Produces(MediaType.APPLICATION_JSON)
public Response findBy...(...,@Context Request request) {
       ... result = ...fetch-result-or-parts-of-it...;
       final EntityTag eTag = new EntityTag(computeETagValue(result),true);
       ResponseBuilder builder = request.evaluatePreconditions(lastModified,eTag);
       if (builder == null) {
              // a new response is required,because the ETag or time stamp do not match
              // ...potentially fetch full result object now,then:
              builder = Response.ok(result);
       } else {
              // a new response is not needed,send "not modified" status without a body
       }
       final CacheControl cacheControl = new CacheControl();
       cacheControl.setPrivate(true); // store in private browser cache of user only
       cacheControl.setMaxAge(15); // may stay unchecked in private browser cache for 15s,afterwards revalidation is required
       cacheControl.setNoTransform(true); // proxies must not transform the response
       return builder
              .cacheControl(cacheControl)
              .lastModified(lastModified)
              .tag(eTag)
              .build();
}

我尝试与Spring MVC REST相同的事情看起来像这样:

@RequestMapping(value="...",produces=MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<...> findByGpnPrefixCacheable(...) {
       ... result = ...fetch-result...;
//     ... result = ...fetch-result-or-parts-of-it...; - can't fetch parts,must obtain full result,see below
       final String eTag = "W/""+computeETagValue(result)+"""; // need to manually construct,as opposed to convenient JAX RS above
       return ResponseEntity
              .ok() // always say 'ok' (200)?
              .cacheControl(
                     CacheControl
                           .cachePrivate()
                           .maxAge(15,TimeUnit.SECONDS)
                           .noTransform()
                     )
              .eTag(eTag)
              .body(result); // ETag comparison takes place outside controller(?),but data for a full response has already been built - that is wasteful!
}

即使不需要,我也需要先建立所有的数据以获得完整的响应.这使得在Spring MVC REST中使用的ETag远远不如它可能是有价值的.对我的理解,一个弱的ETag的想法是,建立它的价值可能是“便宜的”,并将其进行比较.在快乐的情况下,这可以防止服务器上的加载.在资源被修改的情况下,当然需要构建完整的响应.

在我看来,通过设计Spring MVC REST目前需要构建完整的响应数据,无论最终是否需要响应的主体.

所以,总结Spring MVC REST的两个问题:

>有等价于evaluatePreconditions()吗?
>是否有更好的方式构建ETag字符串?

谢谢你的想法!

解决方法

是的,有一个等效的方法.

你可以这样使用:

@RequestMapping
public ResponseEntity<...> findByGpnPrefixCacheable(WebRequest request) {

    // 1. application-specific calculations with full/partial data
    long lastModified = ...; 
    String etag = ...;

    if (request.checkNotModified(lastModified,etag)) {
        // 2. shortcut exit - no further processing necessary
        //  it will also convert the response to an 304 Not Modified
        //  with an empty body
        return null;
    }

    // 3. or otherwise further request processing,actually preparing content
    return ...;
}

请注意,有不同版本的checkNotModified方法,lastModified,ETag或两者.

您可以在这里找到文档:Support for ETag and Last-Modified response headers.

是的,但你必须先改变一些事情.

您可以更改计算ETag的方式,以便您无需获取完整的结果.

例如,如果此提取结果是数据库查询,则可以向实体添加一个版本字段,并使用@Version对其进行注释,以便每次修改时会增加该字段,然后将该值用于ETag.

这是做什么的?由于您可以将抓取配置为懒惰,因此您不需要检索实体的所有字段,并且还可以避免将其哈希来构建ETag.只需使用该版本作为ETag字符串.

这是Using @Version in Spring Data project的一个问题.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读