Перейти к содержимому

22. Кэширование HTTP

Remix позволяет управлять HTTP кэшированием через заголовки Cache-Control прямо из loader функций. Это даёт полный контроль над тем, что кэшируется и на сколько.

export async function loader({ params }) {
const post = await getPost(params.slug);
return json(post, {
headers: {
// Публичный кэш на 1 час, stale-while-revalidate на 1 день
"Cache-Control": "public, max-age=3600, stale-while-revalidate=86400",
},
});
}
"Cache-Control": "no-store"
// Использовать для: персональные данные, финансовые данные
"Cache-Control": "no-cache"
// Ресурс кэшируется, но всегда проверяется на свежесть
"Cache-Control": "public, max-age=31536000, immutable"
// Использовать для: статические ресурсы с хэшами в URL
"Cache-Control": "public, max-age=60, stale-while-revalidate=3600"
// Показываем кэш на 60с, обновляем в фоне до 1 часа
export async function loader({ request, params }) {
const post = await getPost(params.slug);
const etag = \`"\${post.updatedAt.getTime()}"\`;
// Если ETag совпадает — возвращаем 304
if (request.headers.get("If-None-Match") === etag) {
return new Response(null, { status: 304 });
}
return json(post, {
headers: {
"Cache-Control": "public, max-age=60",
"ETag": etag,
},
});
}
export async function loader({ request }) {
const acceptLanguage = request.headers.get("Accept-Language");
const lang = parseLanguage(acceptLanguage);
const content = await getLocalizedContent(lang);
return json(content, {
headers: {
"Cache-Control": "public, max-age=3600",
"Vary": "Accept-Language", // разный кэш для разных языков
},
});
}
HTTP Cache (правильный подход в Remix):
✅ Работает без JS
✅ Общий для всех пользователей (CDN)
✅ Стандартные заголовки
✅ Автоматически инвалидируется при навигации
Клиентский кэш (React Query, SWR):
⚠️ Только при наличии JS
⚠️ Только для текущего пользователя
⚠️ Нужна ручная инвалидация
✅ Мгновенные UI обновления

Remix автоматически инвалидирует кэш при:

  • Отправке формы (action вызывается)
  • Программной навигации с revalidate
  • Ручном вызове revalidate()
import { useRevalidator } from "@remix-run/react";
function AutoRefresh() {
const revalidator = useRevalidator();
useEffect(() => {
const id = setInterval(() => {
if (revalidator.state === "idle") {
revalidator.revalidate();
}
}, 30_000); // обновляем каждые 30 секунд
return () => clearInterval(id);
}, [revalidator]);
}