帶有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.pswp.cn/news/370002.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/370002.shtml
英文地址,請注明出處:http://en.pswp.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;