ETags for REST tavasszal
Most jelentettem be az újat Tanulj tavaszt tanfolyam, amelynek középpontjában az 5. tavasz és a tavaszi bakancs 2 alapjai állnak:
>> ELLENŐRIZZE A FOLYAMATOT1. Áttekintés
Ez a cikk a következőkre fog összpontosítani tavasszal az ETags-szal dolgozik, a REST API és a fogyasztási forgatókönyvek integrációs tesztelése becsavar.
2. REST és ETags
Az ETag támogatás hivatalos tavaszi dokumentációjából:
Az ETag (entitás címke) egy HTTP válasz fejléc, amelyet egy HTTP / 1.1 kompatibilis webszerver küld vissza, és amelyet az adott URL tartalmának változásának meghatározására használnak.Az ETagokat két dologra használhatjuk - gyorsítótárra és feltételes kérésekre. A Az ETag értéke hash-ként is felfogható a Response test bájtjaiból számítva. Mivel a szolgáltatás valószínűleg kriptográfiai kivonatoló funkciót használ, a test legkisebb módosítása is drasztikusan megváltoztatja a kimenetet és ezáltal az ETag értékét. Ez csak az erős ETagokra vonatkozik - a protokoll gyenge Etagot is biztosít.
Egy Ha-* fejléc a szokásos GET kérést feltételes GET-vé alakítja. A két Ha-* Az ETags-szal együtt használt fejlécek az „If-None-Match” és az „If-Match” - mindegyiknek megvan a maga szemantikája, amint azt a cikk később tárgyalja.
3. Ügyfél-kiszolgáló kommunikáció becsavar
Egy egyszerű kliens-szerver kommunikációt bonthatunk az ETag-okkal:
Először az ügyfél REST API-hívást indít - a Válasz tartalmazza az ETag fejlécet amelyeket további felhasználásra tárolunk:
curl -H "Accept: application / json" -i // localhost: 8080 / spring-boot-rest / foos / 1
HTTP / 1.1 200 OK ETag: "f88dd058fe004909615a64f01be66a7" Content-Type: application / json; charset = UTF-8 Content-Length: 52
A következő kéréshez az Ügyfél felveszi a Ha-nincs-meccs kérjen fejlécet az előző lépés ETag értékével. Ha az erőforrás nem változott a szerveren, a válasz nem tartalmaz törzset és állapotkódot 304-ből - Nincs módosítva:
curl -H "Accept: application / json" -H 'If-None-Match: "f88dd058fe004909615a64f01be66a7"' -i // localhost: 8080 / spring-boot-rest / foos / 1
HTTP / 1.1 304 Nem módosított ETag: "f88dd058fe004909615a64f01be66a7"
Mielőtt újra lekérné az erőforrást, változtassunk rajta egy frissítés végrehajtásával:
curl -H "Content-Type: application / json" -i -X PUT --data '{"id": 1, "name": "Transformers2"}' // localhost: 8080 / spring-boot-rest / foos / 1
HTTP / 1.1 200 OK ETag: "d41d8cd98f00b204e9800998ecf8427e" Tartalom-hossz: 0
Végül kiküldjük az utolsó kérést a Foo visszaszerzésére. Ne feledje, hogy a legutóbbi kérés óta frissítettük, ezért a korábbi ETag-érték már nem működhet. A válasz tartalmazza az új adatokat és egy új ETag-et, amely ismét felhasználható:
curl -H "Accept: application / json" -H 'If-None-Match: "f88dd058fe004909615a64f01be66a7"' -i // localhost: 8080 / spring-boot-rest / foos / 1
HTTP / 1.1 200 OK ETag: "03cb37ca667706c68c0aad4cb04c3a211" Content-Type: application / json; charset = UTF-8 Content-Length: 56
És itt van - az ETags a vadonban, és megtakarítja a sávszélességet.
4. ETag támogatás tavasszal
Tovább a tavaszi támogatáshoz: az ETag használata tavasszal rendkívül egyszerűen beállítható és teljesen átlátható az alkalmazás számára. Engedélyezhetjük a támogatást egy egyszerű hozzáadásával Szűrő ban,-ben web.xml:
etagFilter org.springframework.web.filter.ShallowEtagHeaderFilter etagFilter / foos / *
A szűrőt ugyanazon URI mintán térképezzük fel, mint maga a RESTful API. Maga a szűrő az ETag funkcionalitás standard megvalósítása a 3.0 tavasz óta.
A megvalósítás sekély - az alkalmazás a válasz alapján kiszámítja az ETag-t, ami megspórolja a sávszélességet, a szerver teljesítményét azonban nem.
Tehát, egy olyan kérés, amely részesül az ETag támogatásból, továbbra is standard kérésként kerül feldolgozásra, elfogyaszt minden olyan erőforrást, amelyet normálisan fogyasztana (adatbázis-kapcsolatok stb.), És az ETag támogatás csak azelőtt kapja meg a válaszát, hogy visszajuttatná a klienshez. ban ben.
Ekkor az ETag kiszámítása a Válasz testből történik, és magára az Erőforrásra lesz beállítva; is, ha a Ha-nincs-meccs fejléc volt beállítva a Request-en, azt is kezelni fogjuk.
Az ETag-mechanizmus mélyebb megvalósítása potenciálisan sokkal nagyobb előnyökkel járhat - például kiszolgálhat néhány kérést a gyorsítótárból, és egyáltalán nem kell elvégeznie a számítást -, de a megvalósítás határozottan nem lenne olyan egyszerű és nem is olyan plug-in, mint a sekély megközelítés itt leírt.
4.1. Java alapú konfiguráció
Lássuk, hogyan nézne ki a Java-alapú konfiguráció kijelentve a ShallowEtagHeaderFilter bab tavaszi kontextusunkban:
@Bean public ShallowEtagHeaderFilter shallowEtagHeaderFilter () {return new ShallowEtagHeaderFilter (); }
Ne feledje, hogy ha további szűrőkonfigurációkat kell megadnunk, akkor ehelyett kijelenthetjük a FilterRegistrationBean példa:
@Bean public FilterRegistrationBean shallowEtagHeaderFilter () {FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean (új ShallowEtagHeaderFilter ()); filterRegistrationBean.addUrlPatterns ("/ foos / *"); filterRegistrationBean.setName ("etagFilter"); return filterRegistrationBean; }
Végül, ha nem a Tavaszi indítást használjuk, akkor a AbstractAnnotationConfigDispatcherServletInitializer’S getServletFilters módszer.
4.2. A ResponseEntity's használata eTag () Módszer
Ezt a módszert bevezették a 4.1 tavaszi keretbe, és használhatjuk az ETag érték vezérlésére, amelyet egyetlen végpont lekér.
Tegyük fel például, hogy verziószámos entitásokat használunk Optimist zárolási mechanizmusként az adatbázisunkhoz való hozzáféréshez.
Magát a verziót használhatjuk ETag-ként annak jelzésére, hogy az entitás módosult-e:
@GetMapping (value = "/ {id} / custom-etag") public ResponseEntity findByIdWithCustomEtag (@PathVariable ("id") final Long id) {// ... Foo foo = ... return ResponseEntity.ok (). eTag (Long.toString (foo.getVersion ())) .body (foo); }
A szolgáltatás lekéri a megfelelőt 304-Nincs módosítva adja meg, hogy a kérés feltételes fejléce megegyezik-e a gyorsítótár adataival.
5. Az ETags tesztelése
Kezdjük egyszerűen - ellenőriznünk kell, hogy az egyetlen erőforrást lekérő egyszerű kérés válasza valóban visszaadja-e aETag ” fejléc:
@Test public void givenResourceExists_whenRetrievingResource_thenEtagIsAlsoReturned () {// Adott karakterlánc uriOfResource = createAsUri (); // When Response findOneResponse = RestAssured.given (). fejléc ("Elfogadás", "alkalmazás / json"). get (uriOfResource); // Ezután assertNotNull (findOneResponse.getHeader ("ETag")); }
Következő, ellenőrizzük az ETag viselkedés boldog útját. Ha a Kérés a letöltésére a Forrás a szerverről a helyeset használja ETag értéket, akkor a kiszolgáló nem tölti be az erőforrást:
@Test public void givenResourceWasRetrieved_whenRetrievingAgainWithEtag_thenNotModifiedReturned () {// Adott karakterlánc uriOfResource = createAsUri (); Válasz findOneResponse = RestAssured.given (). fejléc ("Elfogadás", "alkalmazás / json"). get (uriOfResource); Karakterlánc etagValue = findOneResponse.getHeader (HttpHeaders.ETAG); // Amikor a Response secondFindOneResponse = RestAssured.given (). header ("Accept", "application / json"). fejlécek ("If-None-Match", etagValue) .get (uriOfResource); // Ezután assertTrue (secondFindOneResponse.getStatusCode () == 304); }
Lépésről lépésre:
- létrehozunk és beolvasunk egy erőforrást, tárolás a ETag érték
- küldjön új lekérési kérelmet, ezúttal a “Ha-nincs-meccs”Fejléc a ETag korábban tárolt érték
- erre a második kérésre a szerver egyszerűen visszaad egy a-t 304 Nincs módosítva, mivel maga az erőforrás valóban nem módosult a két visszakeresési művelet között
Végül ellenőrizzük azt az esetet, amikor az erőforrás megváltozik az első és a második lekérési kérelem között:
@Test public void givenResourceWasRetrievedThenModified_whenRetrievingAgainWithEtag_thenResourceIsReturned () {// Adott karakterlánc uriOfResource = createAsUri (); Válasz findOneResponse = RestAssured.given (). fejléc ("Elfogadás", "alkalmazás / json"). get (uriOfResource); Karakterlánc etagValue = findOneResponse.getHeader (HttpHeaders.ETAG); existingResource.setName (randomAlphabetic (6)); frissítés (existingResource); // Amikor a Response secondFindOneResponse = RestAssured.given (). header ("Accept", "application / json"). fejlécek ("If-None-Match", etagValue) .get (uriOfResource); // Ezután assertTrue (secondFindOneResponse.getStatusCode () == 200); }
Lépésről lépésre:
- először létrehozunk és visszakeresünk a Forrás - és tárolja a ETag érték további felhasználásra
- akkor ugyanezt frissítjük Forrás
- küldjön egy új GET kérést, ezúttal a “Ha-nincs-meccs”Fejléc a ETag amit korábban tároltunk
- erre a második kérésre a szerver visszaadja a 200 OK a teljes erőforrással együtt, mivel a ETag Az érték már nem helyes, mivel időközben frissítettük az Erőforrást
Végül az utolsó teszt - amely nem fog menni, mert a funkcionalitást még nem hajtották végre tavasszal - az a. támogatása If-Match HTTP fejléc:
@Test public void givenResourceExists_whenRetrievedWithIfMatchIncorrectEtag_then412IsReceived () {// Adott T existingResource = getApi (). Create (createNewEntity ()); // Amikor a karakterlánc uriOfResource = baseUri + "/" + existingResource.getId (); Válasz findOneResponse = RestAssured.given (). Fejléc ("Elfogadás", "alkalmazás / json"). fejlécek ("If-Match", randomAlphabetic (8)). get (uriOfResource); // Ezután assertTrue (findOneResponse.getStatusCode () == 412); }
Lépésről lépésre:
- létrehozunk egy Erőforrást
- majd töltse le a „If-Match”Címsor hibásat ad meg ETag érték - ez egy feltételes GET kérés
- a szervernek vissza kell adnia a 412 Nem sikerült az előfeltétel
6. Az ETags nagyok
Csak olvasási műveletekhez használtunk ETag-okat. RFC létezik, amely megpróbálja tisztázni, hogy miként kell a megvalósításoknak kezelniük az ETagokat az írási műveleteknél - ez nem szokványos, de érdekes olvasmány.
Természetesen az ETag mechanizmusnak más lehetőségei is vannak, mint például egy optimista zárszerkezet, valamint a kapcsolódó „Elveszett frissítési probléma” kezelése.
Az ETags használatakor számos ismert lehetséges buktató és figyelmeztetés is van.
7. Következtetés
Ez a cikk csak a felületet karcolta meg azzal, ami a Spring és az ETags segítségével lehetséges.
Az ETag-kompatibilis RESTful szolgáltatás teljes körű megvalósításához, valamint az ETag viselkedését igazoló integrációs tesztekkel együtt nézze meg a GitHub projektet.
REST alsó