middle
Как работает кэширование в REST?
Кэширование — одно из шести ограничений REST, реализуемое через HTTP-заголовки Cache-Control, ETag и Last-Modified для снижения нагрузки на сервер и ускорения ответов клиенту.
1. Cache-Control
Заголовок, управляющий политикой кэширования:
Пример
Cache-Control: max-age=3600 — кэшировать на 1 час
Cache-Control: no-cache — проверять актуальность при каждом запросе
Cache-Control: no-store — не кэшировать вообще
Cache-Control: public, max-age=86400 — кэшировать публично на 24 часа
Cache-Control: private, max-age=600 — кэшировать только на клиенте
2. ETag (Entity Tag)
Сервер возвращает хеш содержимого ресурса. Клиент при повторном запросе отправляет его для проверки:
Пример
Первый запрос:
GET /api/users/42 → 200 OK, ETag: "33a64df..."
Повторный запрос:
GET /api/users/42, If-None-Match: "33a64df..."
→ 304 Not Modified (если ресурс не изменился)
3. Last-Modified / If-Modified-Since
Аналогичен ETag, но использует дату последнего изменения:
Пример
Ответ: Last-Modified: Fri, 10 Jan 2025 12:00:00 GMT
Повторный запрос: If-Modified-Since: Fri, 10 Jan 2025 12:00:00 GMT
→ 304 Not Modified (если не изменился)
Реализация в Spring
Shallow ETag (Spring автоматически считает ETag от тела ответа):
@Configuration
public class WebConfig {
@Bean
public FilterRegistrationBean<ShallowEtagHeaderFilter> shallowEtagHeaderFilter() {
FilterRegistrationBean<ShallowEtagHeaderFilter> filter =
new FilterRegistrationBean<>(new ShallowEtagHeaderFilter());
filter.addUrlPatterns("/api/*");
return filter;
}
}
Ручное управление кэшированием:
@GetMapping("/users/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
User user = userService.findById(id);
return ResponseEntity.ok()
.cacheControl(CacheControl.maxAge(Duration.ofMinutes(30)))
.eTag(String.valueOf(user.getVersion()))
.lastModified(user.getUpdatedAt().toInstant())
.body(user);
}
// Условный запрос с ETag
@GetMapping("/users/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id,
WebRequest request) {
User user = userService.findById(id);
String etag = String.valueOf(user.getVersion());
if (request.checkNotModified(etag)) {
return null; // Spring вернёт 304 автоматически
}
return ResponseEntity.ok()
.eTag(etag)
.body(user);
}
На собеседовании: нужно знать три механизма (Cache-Control, ETag, Last-Modified) и код 304 Not Modified. Частая ошибка — путать no-cache (проверять актуальность) и no-store (не кэшировать вообще).