rest spring_带有Spring的REST的ETag

rest spring

1.概述

本文将重点介绍ETag – Spring支持,RESTful API的集成测试以及带有curl的使用场景。 这是关于使用Spring 3.1和Spring Security 3.1和基于Java的配置来建立安全的RESTful Web服务的系列文章的第9篇。

REST with Spring系列:

  • 第1部分 – 使用Spring 3.1和基于Java的配置引导Web应用程序
  • P艺术2 - 构建RESTful Web服务使用Spring 3.1和Java配置
  • P艺术3 - 保护RESTful Web服务使用Spring Security 3.1
  • 第4部分 – RESTful Web服务可发现性
  • 第5部分 – 使用Spring进行REST服务发现
  • 第6部分 – 使用Spring Security 3.1的RESTful服务的基本身份验证和摘要身份验证
  • 第7部分 – Spring的REST分页
  • 第8部分 – 使用Spring Security对RESTful服务进行身份验证

2. REST和ETag

从有关ETag支持的Spring官方文档中:

ETag (实体标签)是HTTP / 1.1兼容的Web服务器返回的HTTP响应标头,用于确定给定URL的内容更改。

ETag用于两件事–缓存和条件请求。 ETag值可以作为从Response主体的字节中计算出的哈希值 。 因为可能使用加密哈希函数,所以即使是正文的最小修改也将极大地改变输出,从而改变ETag的值。 这仅适用于强大的ETag-该协议也提供了较弱的Etag 。

使用If- *标头会将标准GET请求转换为条件GET 。 与ETag一起使用的两个If- *标头是“ If-None-Match ”和“ If-Match ” –各自具有自己的语义,如本文稍后所述。

3.使用

涉及ETag的简单的Client-Server通信可以分为以下步骤:

首先 ,客户端进行REST API调用–响应包括要存储以供进一步使用的ETag标头:

curl -H 'Accept: application/json' -i http://localhost:8080/rest-sec/api/resources/1
HTTP/1.1 200 OK
ETag: 'f88dd058fe004909615a64f01be66a7'
Content-Type: application/json;charset=UTF-8
Content-Length: 52

–客户端对RESTful API发出的下一个请求包括带有上一步中的ETag值的If-None-Match请求标头; 如果服务器上的资源未更改,则响应将不包含任何正文,并且状态代码为304 –未修改

curl -H 'Accept: application/json' -H 'If-None-Match: 'f88dd058fe004909615a64f01be66a7''-i http://localhost:8080/rest-sec/api/resources/1
HTTP/1.1 304 Not Modified
ETag: 'f88dd058fe004909615a64f01be66a7'

现在 ,在再次检索资源之前,我们将通过执行更新来对其进行更改:

curl --user admin@fake.com:adminpass -H 'Content-Type: application/json' -i-X PUT --data '{ 'id':1, 'name':'newRoleName2', 'description':'theNewDescription' }'
http://localhost:8080/rest-sec/api/resources/1
HTTP/1.1 200 OK
ETag: 'd41d8cd98f00b204e9800998ecf8427e'
<strong>Content-Length: 0</strong>

最后 ,我们发出了最后一个请求以再次获取特权; 请记住,自上次检索以来已对其进行了更新,因此以前的ETag值将不再起作用-响应将包含新数据和新ETag,这些ETag可以再次存储以备后用:

curl -H 'Accept: application/json' -H 'If-None-Match: 'f88dd058fe004909615a64f01be66a7'' -i
http://localhost:8080/rest-sec/api/resources/1
HTTP/1.1 200 OK
ETag: '03cb37ca667706c68c0aad4cb04c3a211'
Content-Type: application/json;charset=UTF-8
Content-Length: 56

一切就在这里– ETags狂野地节省了带宽。

4. Spring对ETag的支持

对Spring的支持–在Spring中使用ETag非常容易设置,并且对应用程序完全透明 。 通过在web.xml中添加一个简单的Filter来启用该支持:

<filter><filter-name>etagFilter</filter-name><filter-class>org.springframework.web.filter.ShallowEtagHeaderFilter</filter-class>
</filter>
<filter-mapping><filter-name>etagFilter</filter-name><url-pattern>/api/*</url-pattern>
</filter-mapping>

筛选器映射到与RESTful API本身相同的URI模式。 从Spring 3.0开始,过滤器本身就是ETag功能的标准实现。

该实现是一个浅层实现-根据响应计算ETag,这将节省带宽,不能 节省 服务器性能 。 因此,将受益于ETag支持的请求仍将作为标准请求处理,消耗通常会消耗的任何资源(数据库连接等),并且只有在将其响应返回给客户端之前,ETag支持才会启动在。

届时,ETag将从响应主体中计算出来,并在资源本身上设置; 同样,如果在请求中设置了If-None-Match标头,则也会对其进行处理。

ETag机制的更深层实现可能会带来更大的好处-例如为缓存中的某些请求提供服务,而根本不必执行计算-但这种实现绝非像浅层方法那样简单,也不可插入在这里描述。

5.测试ETag

让我们开始简单–我们需要验证检索单个Resource的简单请求的响应是否实际上将返回“ ETag”标头:

@Test
public void givenResourceExists_whenRetrievingResource_thenEtagIsAlsoReturned() {// GivenResource existingResource = getApi().create(new Resource());String uriOfResource = baseUri + '/' + existingResource.getId();// WhenResponse findOneResponse = RestAssured.given().header('Accept', 'application/json').get(uriOfResource);// ThenassertNotNull(findOneResponse.getHeader(HttpHeaders.ETAG));
}

接下来我们验证ETag行为的幸福路径 –如果从服务器检索资源的请求使用正确的ETag值,则不再返回资源。

@Test
public void givenResourceWasRetrieved_whenRetrievingAgainWithEtag_thenNotModifiedReturned() {// GivenT existingResource = getApi().create(createNewEntity());String uriOfResource = baseUri + '/' + existingResource.getId();Response findOneResponse = RestAssured.given().header('Accept', 'application/json').get(uriOfResource);String etagValue = findOneResponse.getHeader(HttpHeaders.ETAG);// WhenResponse secondFindOneResponse= RestAssured.given().header('Accept', 'application/json').headers('If-None-Match', etagValue).get(uriOfResource);// ThenassertTrue(secondFindOneResponse.getStatusCode() == 304);
}

一步步:

  • 首先创建资源 ,然后再检索–存储ETag值以备将来使用
  • 发送新的检索请求,这次使用“ If-None-Match ”标题指定先前存储的ETag
  • 在第二个请求上,服务器仅返回304 Not Modified ,因为在两个检索操作之间资源本身确实没有被修改。

最后 ,我们验证在第一个和第二个检索请求之间更改资源的情况:

@Test
public void givenResourceWasRetrieved_whenRetrievingAgainWithEtag_thenNotModifiedReturned() {// GivenT existingResource = getApi().create(createNewEntity());String uriOfResource = baseUri + '/' + existingResource.getId();Response findOneResponse = RestAssured.given().header('Accept', 'application/json').get(uriOfResource);String etagValue = findOneResponse.getHeader(HttpHeaders.ETAG);existingResource.setName(randomAlphabetic(6))getApi().update(existingResource.setName(randomString));// WhenResponse secondFindOneResponse= RestAssured.given().header('Accept', 'application/json').headers('If-None-Match', etagValue).get(uriOfResource);// ThenassertTrue(secondFindOneResponse.getStatusCode() == 200);
}

一步步:

  • 首先创建资源 ,然后再检索–存储ETag值以备将来使用
  • 然后更新相同的资源
  • 发送新的检索请求,这次使用“ If-None-Match ”标题指定先前存储的ETag
  • 在第二个请求上,服务器将返回200 OK以及完整的Resource,因为ETag值不再正确,因为与此同时资源已更新

接下来 ,我们测试“ If-Match ”的行为– ShallowEtagHeaderFilter没有为If-Match HTTP标头提供开箱即用的支持(在此JIRA问题上进行了跟踪),因此以下测试应失败:

@Test
public void givenResourceExists_whenRetrievedWithIfMatchIncorrectEtag_then412IsReceived() {// GivenT existingResource = getApi().create(createNewEntity());// WhenString uriOfResource = baseUri + '/' + existingResource.getId();Response findOneResponse = RestAssured.given().header('Accept', 'application/json').headers('If-Match', randomAlphabetic(8)).get(uriOfResource);// ThenassertTrue(findOneResponse.getStatusCode() == 412);
}

一步步:

  • 首先创建资源
  • 然后使用“ If-Match ”标头检索资源,指定错误的ETag值-这是有条件的GET请求
  • 服务器应返回412 Precondition Failed

6. ETag很大

我们仅将ETag用于读取操作 – 存在一个RFC,试图阐明实现方式应如何在写入操作中处理ETag –这不是标准的,但很有趣。

当然,ETag机制还有其他可能的用途,例如使用Spring 3.1的乐观锁机制以及处理相关的“丢失更新问题” 。

使用ETag时,还要注意一些已知的潜在陷阱和警告 。

7.结论

本文仅介绍了Spring和ETags所能提供的功能。 要全面实现启用了ETag的RESTful服务,以及用于验证ETag行为的集成测试,请查看github项目 。

参考:来自badung博客的JCG合作伙伴 Eugen Paraschiv的Spring的ETags 。

翻译自: https://www.javacodegeeks.com/2013/01/etags-for-rest-with-spring.html

rest spring

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/349995.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL最早版本源码_MySQL旧版本升级为新版本

一&#xff1a;从版本3.23升级到4.104.10新特性&#xff1a;支持事务处理和存储过程升级过程的注意事项&#xff1a;1:升级采用直接复制安装文件的方法&#xff0c;简单实用&#xff0c;但要注意相关的配置更改&#xff1b; 2:直接复制备份的数据库不能通过复制的方法恢复&…

关于国产科学软件的思考(转)

转自 http://blog.pfan.cn/eMath/24264.html 作者 爱数学 http://blog.pfan.cn/eMath 原文如下&#xff1a; 这一段一直在问自己这个问题&#xff1a;“在我们常用的科学计算软件当中&#xff0c;有多少国产的&#xff1f;”&#xff0c;在记忆里面搜索了很久&#xff0c;似乎…

每个私有静态方法都是新类的候选人

您是否有私有的静态方法来帮助您将算法分解为更小的部分&#xff1f; 我做。 每次编写新方法时&#xff0c;我都会意识到它可以是一个新类。 当然&#xff0c;我不会从所有课程中选修课程&#xff0c;但这是目标。 私有静态方法不可重用&#xff0c;而类则可重用&#xff0c;这…

448. Find All Numbers Disappeared in an Array

一、题目 1、审题  2、分析 一个整形数组&#xff01;元素值为 1~size; 出现的元素次数为 1~2 次。 求出所有 1~size 中没有出现的整数&#xff01; 二、解答 1、思路 由于元素值都为 1~size之间。所以可以将数组下标 index 进行联系。 ① 遍历数组&#xff0c;将出现的元素值…

枚举:如何正确使用name()和toString()方法

两种方法之间的区别&#xff1f; Java枚举有两种方法来检索枚举常量的值&#xff1a; name&#xff08;&#xff09;和.toString&#xff08;&#xff09; 。 toString&#xff08;&#xff09;方法调用name&#xff08;&#xff09;方法&#xff0c;该方法返回枚举常量的字符串…

gradle maven_Gradle – Maven的观点

gradle maven正如我博客的读者所知道的&#xff0c; 我有点像Maven迷 。 我从2007年8月左右开始使用Maven&#xff0c;从没有回过头。 但是&#xff0c;与其他所有情况一样&#xff0c;“变化是唯一的常数”。 现在这个领域还有其他参与者&#xff0c;Gradle似乎是最有前途的。…

JDK 9中已弃用Java的Observer和Observable

在博客文章《 应用JDK 9 Deprecated增强功能》中 &#xff0c;我讨论了JDK 9中 Deprecated批注中对forRemoval&#xff08;&#xff09;和since&#xff08;&#xff09;可选元素&#xff08;方法&#xff09;的添加 。 我在那篇文章中说&#xff1a;“在Java SE API上应用新的…

理解依赖注入(IOC)和学习Unity

IOC:英文全称&#xff1a;Inversion of Control&#xff0c;中文名称&#xff1a;控制反转&#xff0c;它还有个名字叫依赖注入&#xff08;Dependency Injection&#xff09;。 作用&#xff1a;将各层的对象以松耦合的方式组织在一起&#xff0c;解耦&#xff0c;各层对象的调…

java中怎样验证重复文件_java – 如何在下载之前检查URL中的重复文件

如果您有基本URL并存储具有相同文件名的文件.由于文件修改时间和If-Modified-Since HTTP Header,您可以询问服务器是否值得再次下载映像.File f new File();// the file to downloadHttpURLConnection con (HttpURLConnection) new URL("http://www.test.com/"f.ge…

Jason是炮王

Jason是炮王 转载于:https://www.cnblogs.com/TankJam/p/11203636.html

事件传递 java_将事件传递/发送到父组件?

在Angular中&#xff0c;我可以创建一个发出动作的子组件&#xff1a;Component({...template: Click Me})export class ChildComponent {Output() onChildAction new EventEmitter();childAction() {this.onChildAction.emit();}}以及处理它的父组件 . 就像是&#xff1a;Com…

mongodb身份验证_MongoDB身份验证

mongodb身份验证我最近更新了Mongometer &#xff0c;使其更加灵活。 发布新版本后不久&#xff0c;其中一位用户通过在帖子中发表评论来反馈问题。 我启动了我的机器&#xff0c;打开了我的IDE&#xff0c;发现了问题&#xff0c;并在半小时内将修补程序推送到了github 。 这不…

mysql列类型

http://hi.baidu.com/b37798969/item/429fb25f838f1d3233e0a99b MySQL支持大量的列类型&#xff0c;它可以被分为3类&#xff1a;数字类型、日期和时间类型以及字符串(字符)类型。本节首先给出可用类型的一个概述&#xff0c;并且总结每个列类型的存储需求&#xff0c;然后提供…

Java13的API_JAVA基础--JAVA API常见对象(其他API)13

一、其他API1.System类system类中的方法和成员变量都是静态的&#xff0c; 不需要创建System对象就可以直接使用。1 /*2 * 演示System的使用3 */4 public classSystemDemo {5 public static voidmain(String[] args) {67 /*8 * System类中的静态成员变量&#xff1a; out 和 er…

适用于Java开发人员的Elasticsearch:简介

本文是我们学院课程的一部分&#xff0c;该课程的标题为Java开发人员的Elasticsearch教程 。 在本课程中&#xff0c;我们提供了一系列教程&#xff0c;以便您可以开发自己的基于Elasticsearch的应用程序。 我们涵盖了从安装和操作到Java API集成和报告的广泛主题。 通过我们简…

人民邮电出版社图灵公司的两本SQL Server 2005图书诚征译者

人民邮电出版社图灵公司介绍&#xff08;来自http://www.turingbook.com/&#xff09; 北京图灵文化发展有限公司成立于2005年6月&#xff0c;由人民邮电出版社投资控股&#xff0c;以策划出版高质量的科技书籍为核心业务&#xff0c;主要出版领域包括计算机、电子电气、数学统…

java容器类继承_JAVA容器 - weslie - OSCHINA - 中文开源技术交流社区

一、 数组1、数组是保存一组对象的最有效的方式。但数组有固定的尺寸而受限(p216)2、数组与其他种类的容器之间的区别有三方面&#xff1a;效率、类型和保存基本类型的能力。在Java中&#xff0c;数组是一种效率最高的存储和随机访问对象引用序列的方式。数组就是一个简单的线性…

前端通信

Node中的net模块提供的前端通信 H5提供的 webSocket 【 常用于 移动端 】pc端低版本浏览器使用 socket.io 通信- 服务端&#xff1a; 总的服务器 举例&#xff1a; 腾讯的qq服务器 1个整体- 客户端&#xff1a; 单个用户使用应用 举例&#xff1a; 每个人的qq 多个client.js 客…

java定位线程阻塞_Arthas - 定位 Java 性能问题原来这么简单

目录&#xff1a;一、Arthas 介绍二、Arthas 使用场景三、Arthas怎么使用四、Arthas 定位性能问题定位Java代码导致占用CPU高的问题线程死锁前言&#xff1a;在做性能测试的过程中&#xff0c;当遇到Java性能问题&#xff0c;比如CPU飙升&#xff0c;负载突高&#xff0c;内存溢…

SVN 本地文件锁/服务端文件锁清除步骤

1.本地文件锁&#xff0c;直接cleanup&#xff0c;cleanup界面选择break locks即可 2.服务端文件锁&#xff0c;本地文件右击没有release lock或者break lock的选项时 方法1&#xff1a;右键&#xff0c;svn选择browser repo&#xff0c;找到该文件&#xff0c;右击&#xff0c…