Короткий ответ
Cache-Control задаёт политику кэширования (сколько времени ответ можно считать свежим), ETag/Last-Modified позволяют клиенту делать условный запрос и получать 304 Not Modified вместо полного тела, если ресурс не изменился, — это снижает нагрузку на сервер и сеть при повторных запросах к не изменившимся данным.
Как это работает подробнее
сервер при первом ответе отдаёт ETag (хэш или версию содержимого) или Last-Modified (время последнего изменения); при следующем запросе клиент передаёт If-None-Match/If-Modified-Since, и сервер, если данные не изменились, отвечает 304 с пустым телом, экономя трафик на передаче неизменного содержимого.
Пример кода
example.py
import hashlib
from fastapi import FastAPI, Request, Response
app = FastAPI()
@app.get("/catalog/{item_id}")
def get_item(item_id: int, request: Request, response: Response):
item = fetch_item(item_id)
etag = hashlib.sha256(str(item).encode()).hexdigest()
if request.headers.get("if-none-match") == etag:
return Response(status_code=304)
response.headers["ETag"] = etag
response.headers["Cache-Control"] = "private, max-age=60"
return itemЧто использовать на практике
- Рекомендация. кэширование подходит для GET-эндпоинтов с относительно редко меняющимися данными (каталог товаров, настройки) и требует, чтобы ETag/Last-Modified надёжно отражали фактическое изменение данных — например, ETag можно построить как хэш от содержимого записи или использовать поле
updated_atиз БД. Для часто меняющихся или персонализированных данных (баланс счёта в реальном времени) агрессивное кэширование может привести к показу устаревших данных — нужно явно выбиратьCache-Control: no-store/privateили короткийmax-age.
Подводные камни
- Риски. выставлять ETag, не завязанный на реальное содержимое (например, случайную строку при каждом ответе), из-за чего условные запросы никогда не совпадают и выгода от кэширования теряется; кэшировать ответы, содержащие данные конкретного авторизованного пользователя, с публичным
Cache-Control: public, что может привести к утечке данных одного пользователя другому через общий (shared) кэш/CDN.