HTTP-кешування може значно підвищити продуктивність вебпрограми. HTTP-кешування будується навколо заголовка відповіді Cache-Control і, згодом, умовних заголовків запиту (таких як Last-Modified та ETag). Cache-Control вказує приватним (наприклад, браузеру) та публічним (наприклад, проксі) кешам, як кешувати та повторно використовувати відповіді. Заголовок ETag використовується для умовного запиту, який може призвести до відповіді 304 (NOT_MODIFIED) без тіла, якщо вміст не змінився. ETag можна вважати більш досконалим наступником заголовка Last-Modified.
У цьому розділі описано опції, пов'язані з HTTP-кешуванням, які доступні в Spring Web MVC.
CacheControl
CacheControl надає засоби підтримки для конфігурування параметрів, пов'язаних із заголовком Cache-Control, і приймається за аргумент у низці місць:
-
Контролери
-
Статичні ресурси
У той час як RFC 7234 описує всі можливі директиви для заголовка відповіді Cache-Control, тип CacheControl використовує підхід, орієнтований на конкретні випадки використання, який фокусується на загальних сценаріях:
// Кешування протягом години - "Cache-Control: max-age=3600"
CacheControl ccCacheOneHour = CacheControl.maxAge(1, TimeUnit.HOURS);
// Запобігання кешуванню - "Cache-Control: no-store".
CacheControl ccNoStore = CacheControl.noStore();
// Кешування протягом десяти днів у публічних та приватних кешах,
// Публічний кеш не повинен перетворювати відповідь
// "Cache-Control: max-age=864000, public, no-transform"
CacheControl ccCustom = CacheControl.maxAge(10, TimeUnit.DAYS).noTransform().cachePublic();
// Кешування протягом години - "Cache-Control: max-age=3600"
val ccCacheOneHour = CacheControl.maxAge(1, TimeUnit.HOURS)
// Запобігання кешуванню - "Cache-Control: no-store".
val ccNoStore = CacheControl.noStore()
// Кешування протягом десяти днів у публічних та приватних кешах,
// Публічний кеш не повинен перетворювати відповідь
// "Cache-Control: max-age=864000, public, no-transform"
val ccCustom = CacheControl.maxAge(10, TimeUnit.DAYS).noTransform().cachePublic()
WebContentGenerator також приймає простішу властивість cachePeriod (визначена в секундах), яка працює наступним чином:
-
Значення
-1не генерує заголовок відповідіCache-Control. -
Значення
0запобігає кешуванню за допомогою директиви"Cache-Control: no-store". -
При значенні
n > 0надана відповідь кешується наnсекунд за допомогою директиви"Cache-Control: max-age=n".
Контролери
Контролери можуть додавати явну підтримку HTTP-кешування. Ми рекомендуємо робити це, оскільки значення lastModified або ETag для ресурсу потрібно обчислювати, перш ніж його можна буде порівняти з умовними заголовками запиту. Контролер може додавати заголовок ETag та параметри Cache-Control до ResponseEntity, як показано в наступному прикладі:
@GetMapping("/book/{id}")
public ResponseEntity<Book> showBook(@PathVariable Long id) {
Book book = findBook(id);
String version = book.getVersion();
return ResponseEntity
.ok()
.cacheControl(CacheControl.maxAge(30, TimeUnit.DAYS))
.eTag(version) // lastModified is also available
. body (book);
}
@GetMapping("/book/{id}")
fun showBook(@PathVariable id: Long): ResponseEntity<Book> {
val book = findBook(id);
val version = book.getVersion()
return ResponseEntity
.ok()
.cacheControl(CacheControl.maxAge(30, TimeUnit.DAYS))
.eTag(version) // lastModified is also available
.body(book)
}
У попередньому прикладі відповідь 304 (NOT_MODIFIED) надсилається з порожнім тілом, якщо порівняння з умовними заголовками запиту показує, що вміст не змінився. В іншому випадку до відповіді додаються заголовки ETag та Cache-Control.
Ти також можеш здійснити перевірку на умовні заголовки запиту в контролері, як показано в наступному прикладі:
@RequestMapping
public String myHandleMethod(WebRequest request, Model model) {
long eTag = ...
if (request.checkNotModified(eTag)) {
return null;
}
model.addAttribute(...);
return "myViewName";
}
- Обчислення для конкретної програми.
- Відповідь було встановлено на 304 (NOT_MODIFIED) — подальша обробка заборонена.
- Продовжуємо обробку запиту.
@RequestMapping
fun myHandleMethod(request: WebRequest, model: Model): String? {
val eTag: Long = ...
if (request.checkNotModified(eTag)) {
return null
}
model[...] = ...
return "myViewName"
}
- Обчислення для конкретної програми.
- Відповідь було встановлено на 304 (NOT_MODIFIED) — подальша обробка заборонена.
- Продовжуємо обробку запиту.
Існує три варіанти перевірки умовних запитів на відповідність значенням eTag, значенням lastModified або обом. Для умовних запитів GET та HEAD можна встановити відповідь на 304 (NOT_MODIFIED). Для умовних POST, PUT та DELETE можеш натомість встановити відповідь на 412 (PRECONDITION_FAILED), щоб запобігти одночасній модифікації.
Статичні ресурси
Для оптимальної продуктивності статичні ресурси слід обробляти за допомогою Cache-Control та умовних заголовків відповіді.
Фільтр ETag
ShallowEtagHeaderFilter можна використовувати для додавання "поверхневих" значень eTag, які обчислюються з вмісту відповіді і, таким чином, заощаджують пропускну здатність, але не процесорний час.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ