HTTP-кешування може значно підвищити продуктивність вебпрограми. HTTP-кешування будується навколо заголовка відповіді Cache-Control і, згодом, умовних заголовків запиту, таких як Last-Modified та ETag. Cache-Control вказує приватним (наприклад, браузеру) та публічним (наприклад, проксі) кешам, як кешувати та повторно використовувати відповіді. Заголовок ETag використовується для умовного запиту, який може призвести до відповіді 304 (NOT_MODIFIED) без тіла, якщо вміст не змінився. ETag можна вважати більш досконалим наступником заголовка Last-Modified.

У цьому розділі описано опції, пов'язані з HTTP-кешуванням, які доступні в Spring WebFlux.

CacheControl

CacheControl надає засоби підтримки для конфігурування параметрів, пов'язаних із заголовком Cache-Control, і приймається як аргумент у низці місць:

  • Контролери

  • Статичні ресурси

Поряд з тим, що RFC 7234 описує всі можливі директиви для заголовка відповіді Cache-Control, тип CacheControl використовує підхід, орієнтований на конкретні випадки використання, який фокусується на загальних сценаріях:

Java
// Кешування протягом години — "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();
Kotlin
// Кешування протягом години - "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()

Контролери

Контролери можуть додавати явну підтримку HTTP-кешування. Ми рекомендуємо робити це, оскільки значення lastModified або ETag для ресурсу потрібно обчислювати, перш ніж його можна буде порівняти з умовними заголовками запиту. Контролер може додавати заголовок ETag та параметри Cache-Control до ResponseEntity, як показано в наступному прикладі:

Java
@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);
}
Kotlin
@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.

Ти також можеш здійснити перевірку на умовні заголовки запиту в контролері, як показано в наступному прикладі:

Java
@RequestMapping
public String myHandleMethod(ServerWebExchange exchange, Model model) {
long eTag = ... 
if (exchange.checkNotModified(eTag)) {
return null; 
}
model.addAttribute(...); 
return "myViewName";
}
  1. Обчислення для конкретної програми.
  2. Відповідь було встановлено на 304 (NOT_MODIFIED). Подальшої обробки не відбувається.
  3. Продовжуємо обробку запиту.
Kotlin
@RequestMapping
fun myHandleMethod (exchange: ServerWebExchange, model: Model): String? {
val eTag: Long = ... 
if (exchange.checkNotModified(eTag)) {
return null
}
model.addAttribute(...) 
return "myViewName"
}
  1. Обчислення для конкретної програми.
  2. Відповідь було встановлено на 304 (NOT_MODIFIED). Подальшої обробки не відбувається.
  3. Продовжуємо обробку запиту.

Існує три варіанти перевірки умовних запитів на відповідність значенням eTag, значенням lastModified або обома. Для умовних запитів GET та HEAD можна встановити відповідь на 304 (NOT_MODIFIED). Для умовних POST, PUT та DELETE можна натомість встановити відповідь на 412 (PRECONDITION_FAILED), щоб запобігти одночасній модифікації.

Статичні ресурси

Для оптимальної продуктивності статичні ресурси слід обробляти за допомогою Cache-Control та умовних заголовків відповіді. Див. розділ конфігурування статичних ресурсів.