javascript
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/1HTTP/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/1HTTP/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/1HTTP/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/1HTTP/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
總結
以上是生活随笔為你收集整理的rest spring_带有Spring的REST的ETag的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用Spring Boot自动发布和监视
- 下一篇: 电脑屏幕排线定义(电脑排线和屏线是一个吗