Zaglavlja predmemorije u proljetnom MVC-u

1. Pregled

U ovom uputstvu naučit ćemo o HTTP predmemoriranju. Također ćemo razmotriti razne načine za primjenu ovog mehanizma između klijenta i Spring MVC aplikacije.

2. Predstavljamo HTTP predmemoriranje

Kad otvorimo web stranicu u pregledniku, ona s web poslužitelja obično preuzme puno resursa:

Na primjer, u ovom primjeru preglednik mora preuzeti tri resursa za jedan /prijaviti se stranica. Uobičajeno je da preglednik šalje više HTTP zahtjeva za svaku web stranicu. Ako takve stranice zahtijevamo vrlo često, to uzrokuje puno mrežnog prometa i treba više vremena za njihovo posluživanje.

Kako bi smanjio mrežno opterećenje, HTTP protokol omogućuje preglednicima da predmemoriraju neke od tih resursa. Ako je omogućeno, preglednici mogu spremiti kopiju resursa u lokalnu predmemoriju. Kao rezultat toga, preglednici mogu posluživati ​​ove stranice iz lokalne pohrane, umjesto da to zahtijevaju putem mreže:

Web poslužitelj može usmjeravati preglednik da predmemorira određeni resurs dodavanjem datoteke Kontrola predmemorije zaglavlje u odgovoru.

Budući da su resursi predmemorirani kao lokalna kopija,postoji rizik od posluživanja ustajalog sadržaja iz preglednika. Stoga web poslužitelji obično dodaju vrijeme isteka u Kontrola predmemorije Zaglavlje.

U sljedećim odjeljcima dodati ćemo ovo zaglavlje u odgovoru proljetnog MVC kontrolera. Kasnije ćemo vidjeti i Spring API-je za provjeru predmemoriranih resursa na temelju vremena isteka.

3. Kontrola predmemorije u odgovoru kontrolera

3.1. Koristeći ResponseEntity

Najjednostavniji način za to jekoristiti CacheControl graditeljsku klasu koju je pružio Spring:

@GetMapping ("/ hello / {name}") @ResponseBody javni ResponseEntity hello (@PathVariable String name) {CacheControl cacheControl = CacheControl.maxAge (60, TimeUnit.SECONDS) .noTransform () .mustRevalidate (); vratiti ResponseEntity.ok () .cacheControl (cacheControl) .body ("Zdravo" + ime); }

Ovo će dodati a Kontrola predmemorije zaglavlje u odgovoru:

@Test void whenHome_thenReturnCacheHeader () baca izuzetak {this.mockMvc.perform (MockMvcRequestBuilders.get ("/ hello / baeldung")). And Do (MockMvcResultHandlers.print ()). andExpect (MockMvcResultMatchers.header () .string ("Upravljanje predmemorijom", "max-age = 60, mora se ponovno potvrditi, nema pretvorbe")); }

3.2. Koristeći HttpServletResponse

Često kontrolori trebaju vratiti ime pogleda s metode rukovatelja. MeđutimResponseEntity klasa nam ne dopušta da vratimo ime pogleda i istovremeno se bavimo tijelom zahtjeva.

Alternativno, za takve kontrolere možemo postaviti Kontrola predmemorije zaglavlje u HttpServletResponse direktno:

@GetMapping (value = "/ home / {name}") javni niz home (@PathVariable String ime, konačni odgovor HttpServletResponse) {response.addHeader ("Kontrola predmemorije", "max-age = 60, mora se ponovo potvrditi, ne -transformirati"); Povratak kući"; }

Ovo će također dodati a Kontrola predmemorije zaglavlje u HTTP odgovoru slično prošlom odjeljku:

@Test void whenHome_thenReturnCacheHeader () baca izuzetak {this.mockMvc.perform (MockMvcRequestBuilders.get ("/ home / baeldung")). andExpect (MockMvcResultMatchers.header () .string ("Upravljanje predmemorijom", "max-age = 60, mora se revalidirati, bez pretvorbe")) .andExpect (MockMvcResultMatchers.view (). name ("home")); }

4. Kontrola predmemorije za statičke resurse

Općenito, naša Spring MVC aplikacija služi puno statičkih resursa poput HTML, CSS i JS datoteka. Budući da takve datoteke troše puno mrežne propusnosti, važno je da ih preglednici keširaju. Ponovno ćemo to omogućiti pomoću Kontrola predmemorije zaglavlje u odgovoru.

Proljeće nam omogućuje kontrolu nad ponašanjem predmemoriranja u mapiranju resursa:

@Override public void addResourceHandlers (konačni registar ResourceHandlerRegistry) {registry.addResourceHandler ("/ resources / **"). AddResourceLocations ("/ resources /") .setCacheControl (CacheControl.maxAge (60, TimeUnit.SECrans). mustRevalidate ()); }

To osigurava da svi resursidefinirano pod/resursi vraćaju se s Kontrola predmemorije zaglavlje u odgovoru.

5. Kontrola predmemorije u presretačima

U našoj proljetnoj MVC aplikaciji možemo koristiti presretače za obavljanje neke obrade prije i poslije za svaki zahtjev. Ovo je još jedno rezervirano mjesto gdje možemo kontrolirati ponašanje predmemoriranja aplikacije.

Sada ćemo umjesto implementacije prilagođenog presretača koristiti WebContentInterceptor koje pruža Spring:

@Override public void addInterceptors (registar InterceptorRegistry) {WebContentInterceptor interceptor = new WebContentInterceptor (); presretač.addCacheMapping (CacheControl.maxAge (60, TimeUnit.SECONDS) .noTransform () .mustRevalidate (), "/ login / *"); registry.addInterceptor (presretač); }

Ovdje smo registrirali WebContentInterceptor i dodao Kontrola predmemorije zaglavlje slično posljednjih nekoliko odjeljaka. Značajno je da možemo dodati drugačije Kontrola predmemorije zaglavlja za različite uzorke URL-a.

U gornjem primjeru, za sve zahtjeve koji počinju sa /prijaviti se, dodati ćemo ovo zaglavlje:

@Test void whenInterceptor_thenReturnCacheHeader () baca izuzetak {this.mockMvc.perform (MockMvcRequestBuilders.get ("/ login / baeldung")). AndDo (MockMvcResultHandlers.print ()). andExpect (MockMvcResultMatchers.header () .string ("Upravljanje predmemorijom", "max-age = 60, mora se ponovno potvrditi, nema pretvorbe")); }

6. Provjera predmemorije u proljetnom MVC-u

Do sada smo razgovarali o različitim načinima uključivanja a Kontrola predmemorije zaglavlje u odgovoru. To ukazuje na to da klijenti ili preglednici trebaju predmemorirati resurse na temelju svojstava konfiguracije poput maksimalna dob.

Općenito je dobra je ideja dodati vrijeme isteka predmemorije uz svaki resurs. Kao rezultat toga, preglednici mogu izbjeći posluživanje resursa s predmemorijom kojima je istekao rok trajanja.

Iako bi preglednici uvijek trebali provjeriti da li im je istekao rok trajanja, možda neće biti potrebno ponovno dohvaćanje resursa svaki put. Ako preglednik može potvrditi da se resurs nije promijenio na poslužitelju, može nastaviti služiti njegovu predmemoriranu verziju. U tu svrhu HTTP nam nudi dva zaglavlja odgovora:

  1. Etag - zaglavlje HTTP odgovora koje pohranjuje jedinstvenu vrijednost raspršivanja kako bi se utvrdilo je li se predmemorirani resurs promijenio na poslužitelju - odgovarajuće Ako se ne podudara zaglavlje zahtjeva mora sadržavati zadnju vrijednost Etaga
  2. Zadnja promjena - zaglavlje HTTP odgovora koje pohranjuje vremensku jedinicu kada je izvor zadnji put ažuriran - odgovarajuće Ako-neizmijenjeno-od zaglavlje zahtjeva mora sadržavati datum posljednje izmjene

Bilo koje od ovih zaglavlja možemo koristiti za provjeru treba li resurs koji je istekao trebati ponovno dohvatiti. Nakon provjere zaglavlja,poslužitelj može ponovno poslati resurs ili poslati 304 HTTP kôd što znači da nema promjene. Za potonji scenarij preglednici mogu nastaviti koristiti predmemorirani resurs.

The Zadnja promjena zaglavlje može pohraniti vremenske intervale do preciznosti do nekoliko sekundi. To može biti ograničenje u slučajevima kada je potreban kraći istek. Iz tog razloga preporučuje se korištenje Etag umjesto toga. Od Etag zaglavlje pohranjuje hash vrijednost, moguće je stvoriti jedinstveno hash do finijih intervala poput nanosekundi.

Usput, provjerimo kako to izgleda koristiti Zadnja promjena.

Spring pruža neke korisne metode za provjeru sadrži li zahtjev zaglavlje isteka ili ne:

@GetMapping (value = "/ productInfo / {name}") javna ResponseEntity provjera valjanosti (@PathVariable String name, WebRequest zahtjev) {ZoneId zoneId = ZoneId.of ("GMT"); long lastModifiedTimestamp = LocalDateTime.of (2020, 02, 4, 19, 57, 45) .atZone (zoneId) .toInstant (). toEpochMilli (); if (request.checkNotModified (lastModifiedTimestamp)) {return ResponseEntity.status (304) .build (); } return ResponseEntity.ok (). body ("Zdravo" + ime); }

Proljeće pruža checkNotModified () metoda za provjeru je li resurs promijenjen od zadnjeg zahtjeva:

@Test void whenValidate_thenReturnCacheHeader () baca iznimku {HttpHeaders headers = new HttpHeaders (); headers.add (IF_UNMODIFIED_SINCE, "Utorak, 04. veljače 2020. 19:57:25 GMT"); this.mockMvc.perform (MockMvcRequestBuilders.get ("/ productInfo / baeldung"). headers (headers)) .andDo (MockMvcResultHandlers.print ()) .andExpect (MockMvcResultMatchers.status (); is (304). }

7. Zaključak

U ovom smo članku saznali više o HTTP predmemoriranju pomoću Kontrola predmemorije zaglavlje odgovora u proljetnom MVC-u. Možemo dodati zaglavlje u odgovor kontrolera pomoću ResponseEntity klase ili kroz mapiranje resursa za statičke resurse.

Ovo zaglavlje možemo dodati i za određene uzorke URL-a pomoću presretača Spring.

Kao i uvijek, kôd je dostupan na GitHub-u.