带有Spring的REST的ETag

1.概述

本文将重点介绍ETags-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前提条件失败

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

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

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

相关文章

html5与css3都要学吗,前端要学css3吗?

前端要学css3&#xff1b;HTML5、CSS3是前端工程师必须要学会。现在移动端的兴起&#xff0c;导致web前端开发的技术逐变向css3和html5转变&#xff0c;所以css3一定要学。CSS3是CSS(层叠样式表)技术的升级版本&#xff0c;于1999年开始制订&#xff0c;2001年5月23日W3C完成了…

PHP中cookie和session的区别

1、cookie数据存放在客户的浏览器上&#xff0c;session数据放在服务器上。 2、cookie不是很安全&#xff0c;别人可以分析存放在本地的COOKIE并进行COOKIE欺骗考虑到安全应当使用session。 3、session会在一定时间内保存在服务器上。当访问增多&#xff0c;会比较占用你服务器…

ubuntu下anaconda3+pygame

有是很无语的地方&#xff0c;网上教程一堆&#xff0c;又是要下载什么包&#xff0c;然后又是什么依赖乱七八糟的整一堆。都不知道怎么想的 试了 sudo apt-get install python-pygame 这个是行不通的&#xff01;&#xff01;&#xff01;根本没有任何卵用 害我捯饬了半天&am…

react 判断图片是否加载完成_React中型项目的优化实践

项目介绍整个项目大概有60个页面&#xff0c;用到的组件大概150&#xff0c;package里面的依赖大概有70个&#xff0c;应该勉强算得上是一个中型的React的项目了。下面给大家看看我们现在build一次项目的结果--打包时间约150s&#xff0c;打包完之后的资源gzip之后约1.2m&#…

搭建本地wordpress

1.首先&#xff0c;下载xampp&#xff0c;安装按默认勾选即可。 2.安装完成后&#xff0c;启动Apache和MySQL这两个服务。 启动后变成绿色&#xff0c;表示启动成功。 3.点击MySQL项的Admin进入数据库后台。 4.点击用户账户新建用户。 5.填写用户名&#xff0c;host name选本地…

编写Java批注

Java 批注的允许的属性类型刻意非常严格&#xff0c;但是允许的类型也可以使用一些简洁的复合批注类型。 考虑教程站点中的示例注释&#xff1a; package annotation; interface ClassPreamble {String author();String[] reviewers(); }在这里&#xff0c;作者和审阅者具有St…

Python基础【day02】:字符串(四)

在Python中字符串本身有带很多操作&#xff0c;字符串的特性&#xff0c;不可以被修改 0、字符串常用功能汇总 1、字符串的定义 #定义空字符串>>> name#定义非空字符串 >>> name"luoahong"#通过下标访问 >>> name[1] u#不能修改字符串的值…

cryptojs vue 使用_VueJs里利用CryptoJs实现加密及解密

第一步 安装安装crypto-js第二步 创建在js文件目录下创建一个js文件secret/*** 对页面上输入的密码进行加密传输给后台进行验证&#xff0c;对返回的数据进行解密&#xff0c;在页面展示*/let CryptoJS require(crypto-js); // 引入AES源码jsexport default {/** 对密码进行加…

html5 窗口变形,HTML5画布(变形)

坐标变换案例1&#xff1a;function draw(){var cdocument.getElementById("myCanvas");var cxt c.getContext("2d");cxt.translate(200,50);cxt.fillStylergba(255,0,0,0.25);for(var i0;i<40;i){cxt.translate(25,25);cxt.scale(0.9,0.9);cxt.rotate(…

appium GUI介绍

Appium作为APP端的自动化测试工具&#xff0c;具有很多的有点&#xff0c;今天主要介绍一下它的UI界面&#xff0c;包含其中的一些参数等。主要说的是windows下的APPIUM GUI。 先看一眼它的界面(版本为1.4.16.1) 注: 1.android Settings - Android设置按钮&#xff0c;所有和安…

迭代器模式和Java

大家好&#xff0c;在本文中&#xff0c;我们将检查Iterator Pattern 。 我知道你们中许多人已经使用过一种设计模式&#xff0c;但是也许您没有意识到它是模式&#xff0c;或者不知道它的巨大价值。 根据《 Head First Design 》一书&#xff1a; 迭代器模式提供了一种在不暴…

不使用JavaScript实现菜单的打开和关闭

我在写有菜单栏的网页时&#xff0c;基本都会用响应式设计来适配移动端&#xff0c;例如把不重要的菜单选项隐藏&#xff0c;或者创建一个菜单按钮来控制的菜单的打开和关闭之类的。而我之前一直是使用JavaScript来实现菜单的打开和关闭的&#xff0c;但最近在网上看到有人使用…

负载均衡的几种方式

&#xff08;1&#xff09;HTTP重定向负载均衡。 这种负载均衡方案的优点是比较简单&#xff0c;缺点是浏览器需要每次请求两次服务器才能拿完成一次访问&#xff0c;性能较差。&#xff08;2&#xff09;DNS域名解析负载均衡。 DNS域名解析负载均衡的优点是将负载均衡工作交给…

芝枝.计算机与人文科学,计算机与人文科学

计算机与人文科学(2013-03-13 13:24:17)标签&#xff1a;文化战争名著《静静的顿河》可以说从它诞生起便没有平静过&#xff0c;围绕它的作者所引起的争议&#xff0c;就像它获得诺贝尔文学奖一样&#xff0c;撼动文坛&#xff0c;有人指控肖洛霍夫是个骗子&#xff0c;《静静的…

rto初始化和计算_TCP系列13—重传—3、协议中RTO计算和RTO定时器维护

从上一篇示例中我们可以看到在TCP中有一个重要的过程就是决定何时进行超时重传&#xff0c;也就是RTO的计算更新。由于网络状况可能会受到路由变化、网络负载等因素的影响&#xff0c;因此RTO也必须跟随网络状况动态更新。如果TCP过早重传&#xff0c;则可能会向网络中注入很多…

在Java 8 Lambda上使用Apache Commons Functor功能接口

Apache Commons Functor &#xff08;以下称为[functor]&#xff09;是一个Apache Commons组件&#xff0c;它提供功能性的编程API和已实现的几种模式&#xff08;访问者&#xff0c;生成器&#xff0c;聚合器等&#xff09;。 Java 8具有几个不错的新功能&#xff0c;包括lamb…

HTML5 Canvas游戏开发实战 PDF扫描版

HTML5 Canvas游戏开发实战主要讲解使用HTML5 Canvas来开发和设计各类常见游戏的思路和技巧&#xff0c;在介绍HTML5 Canvas相关特性的同时&#xff0c;还通过游戏开发实例深入剖析了其内在原理&#xff0c;让读者不仅知其然&#xff0c;而且知其所以然。在本书中&#xff0c;除…

多线程之创建线程

在Java中&#xff0c;线程能区分两种不同类型的线程&#xff1a;前台线程和后台线程。这两者的区别就是&#xff1a;应用程序必须运行完所有的前台线程才可以退出&#xff1b;而对于后台线程&#xff0c;应用程序则可以不考虑其是否已经运行完毕而直接退出&#xff0c;所有的后…

阿 Q 的停车场

问题描述 刚拿到驾照的 KJ 总喜欢开着车到处兜风&#xff0c;玩完了再把车停到阿 Q 的停车场里&#xff0c;虽然 她对自己停车的水平很有信心&#xff0c;但她还是不放心其他人的停车水平&#xff0c;尤其是 Kelukin。于是&#xff0c; 她每次都把自己的爱车停在距离其它车最远…

css3图片垂直居中

图片相对父元素垂直居中, css3属性给父级元素设置 display: -webkit-box; -moz-box-align: center; -webkit-box-align: center; -moz-box-pack: center; -webkit-box-pack: center; 需要注意的是&#xff1a; 父级元素要有确定的高度&#xff01;