← Назад к вопросам

Были ли проблемы с кэшированием у приложения с Next.js

2.0 Middle🔥 71 комментариев
#Оптимизация и производительность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Проблемы с кэшированием в Next.js

Кэширование в Next.js — это мощный инструмент для производительности, но он может быть источником серьёзных проблем, если не понимать как он работает. На собеседовании этот вопрос показывает, есть ли опыт работы с production-приложениями.

Основные типы кэширования в Next.js

Next.js имеет несколько слоёв кэширования:

1. Static Generation (SSG) — на build time
2. Incremental Static Regeneration (ISR) — с revalidate
3. Server-Side Rendering (SSR) — не кэшируется
4. Client-side кэширование (fetch, SWR, React Query)
5. CDN кэширование (Vercel, Cloudflare)

Проблема 1: Устаревший контент (Stale Content)

Вероятно самая частая проблема:

// pages/products/[id].js
export async function getStaticProps({ params }) {
  const product = await fetch(`/api/products/${params.id}`).then(r => r.json());
  
  return {
    props: { product },
    revalidate: 60 // перегенерировать каждую минуту
  };
}

// Проблема: если товар изменился, пользователь увидит старые данные в течение 60 секунд
// Критично для e-commerce, где цены и наличие меняются часто

Решение — ISR с более правильными параметрами:

export async function getStaticProps({ params }) {
  const product = await fetchProduct(params.id);
  
  return {
    props: { product },
    revalidate: process.env.NODE_ENV === 'production' ? 10 : false
    // В продакшене перегенерируем каждые 10 секунд
    // В разработке — не кэшируем
  };
}

Проблема 2: Cache не инвалидируется при обновлении данных

Сценарий: пользователь обновил товар, но видит старую версию

// pages/api/products/[id]/update.js
export default async function handler(req, res) {
  if (req.method === 'PUT') {
    const updated = await updateProduct(req.body);
    
    // ❌ Неправильно: не инвалидируем кэш
    res.json(updated);
    
    // ✅ Правильно: инвалидируем кэш
    // Используем On-Demand ISR (Next.js 12.2+)
    await res.revalidate(`/products/${req.body.id}`);
    res.json(updated);
  }
}

Проблема 3: Cache на фронтенде (fetch кэширование)

Next.js 13+ автоматически кэширует fetch запросы (Data Cache):

// app/products/[id]/page.js
async function getProduct(id) {
  const res = await fetch(`/api/products/${id}`);
  // ⚠️ По умолчанию это кэшируется НАВСЕГДА!
  return res.json();
}

// ✅ Правильно: явно указать время кэша
async function getProduct(id) {
  const res = await fetch(`/api/products/${id}`, {
    next: { revalidate: 60 } // перегенерировать каждую минуту
  });
  return res.json();
}

// ✅ Правильно: не кэшировать
async function getProduct(id) {
  const res = await fetch(`/api/products/${id}`, {
    cache: 'no-store' // всегда свежо
  });
  return res.json();
}

Проблема 4: Несоответствие между SSG и SSR

Смешивание SSG и SSR может привести к проблемам:

// ❌ Неправильно: гибридный подход
export async function getStaticProps() {
  // Может быть медленно, если много страниц
  const products = await fetchAllProducts();
  return { props: { products }, revalidate: 60 };
}

// ✅ Правильно: понимать trade-offs
// Для часто изменяемых данных: SSR
export async function getServerSideProps() {
  const products = await fetchAllProducts();
  return { props: { products } };
}

// Для статичных данных: SSG
export async function getStaticProps() {
  const products = await fetchAllProducts();
  return { props: { products }, revalidate: 86400 }; // раз в день
}

Проблема 5: Browser Cache Headers

Неправильные headers могут привести к проблемам на фронтенде:

// pages/api/products/[id].js
export default function handler(req, res) {
  // ❌ Неправильно: браузер кэширует API ответ
  const product = getProduct(req.query.id);
  res.json(product);
  
  // ✅ Правильно: явно указать кэширование
  res.setHeader('Cache-Control', 'public, max-age=60, stale-while-revalidate=120');
  res.json(product);
  
  // ✅ Для приватных данных
  res.setHeader('Cache-Control', 'private, max-age=60');
  res.json(user);
  
  // ✅ Для данных, которые не должны кэшироваться
  res.setHeader('Cache-Control', 'no-store');
  res.json(sensitiveData);
}

Проблема 6: CDN кэширование конфликтует с ISR

Если используешь Cloudflare или другой CDN:

// ❌ Проблема: CDN кэширует HTML, а ISR хочет обновить
// На Cloudflare нужно настроить корректно

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  onDemandEntries: {
    maxInactiveAge: 60 * 1000, // 1 минута
    pagesBufferLength: 5,
  },
};

// Плюс в Cloudflare (если используешь):
// Cache Rule: HTML кэшируется на 1 минуту, а не навсегда

Проблема 7: Проблемы с preview mode

Забывают выключить preview mode в production:

// pages/api/preview.js
export default function handler(req, res) {
  // ❌ Опасно: любой может перейти в preview mode
  if (req.query.secret === 'PREVIEW_SECRET') {
    res.setPreviewData({});
    res.redirect('/');
  }
  
  // ✅ Правильно: проверить токен
  if (req.query.secret !== process.env.PREVIEW_SECRET) {
    return res.status(401).json({ message: 'Unauthorized' });
  }
  
  res.setPreviewData({});
  res.redirect('/');
}

Реальный пример: e-commerce

Мой опыт с проблемой кэширования:

// Ситуация: продаём товары, цена меняется
// Проблема: кэш показал старую цену, потеря продаж

// Решение
export async function getStaticProps({ params }) {
  const product = await db.products.findById(params.id);
  
  return {
    props: { product },
    // Критично: перегенерировать каждую минуту
    revalidate: 60,
    // На продакшене используем стабильный host
  };
}

// Плюс: на-demand инвалидация при обновлении
export default function handler(req, res) {
  if (req.method === 'PUT') {
    const updated = updateProduct(req.body);
    
    // Инвалидируем кэш
    res.unstable_revalidatePath(`/products/${updated.id}`);
    
    res.json(updated);
  }
}

Debugging кэша

// Как проверить кэширование?

// 1. Network tab в DevTools
// Смотрим Status:
// - 200 от сервера
// - 304 Not Modified (браузер кэш)
// - 200 от CDN (X-Cache: HIT)

// 2. Логирование
export async function getStaticProps() {
  console.log('getStaticProps called at', new Date());
  // Вызывается только на build time и при revalidate
}

// 3. Headers
// curl -I https://example.com/products/1
// Смотрим: Cache-Control, ETag, Last-Modified

Best Practices

// 1. Для данных, которые редко меняются (раз в день)
export async function getStaticProps() {
  return { props, revalidate: 86400 };
}

// 2. Для данных, которые часто меняются (каждую минуту)
export async function getServerSideProps() {
  return { props };
}

// 3. Для данных, которые очень часто меняются
// Использовать client-side fetching с SWR или React Query
function Component() {
  const { data } = useSWR('/api/live-data', fetcher, { 
    revalidateOnFocus: true 
  });
}

// 4. На-demand инвалидация
res.unstable_revalidatePath('/products');
res.unstable_revalidatePath('/products/[id]');
res.unstable_revalidatePath('/'); // весь сайт (осторожно!)

На собеседовании

Краткий ответ: Да, встречался с проблемами кэширования. Самая частая — забыли установить revalidate для ISR, и пользователи видят устаревший контент. Также проблемы с fetch кэшированием в App Router, где по умолчанию кэшируется навсегда.

Развёрнутый ответ: Встречался с несколькими типами проблем: 1) ISR без правильного revalidate показывает старый контент; 2) fetch кэширование в App Router кэширует навсегда (нужно cache: no-store); 3) Забывают инвалидировать кэш при обновлении данных (нужно res.revalidatePath); 4) Конфликты с CDN кэшированием (нужны правильные Cache-Control headers); 5) Preview mode оставляют включённым. Решение — использовать ISR для статичных данных, SSR для часто меняющихся, client-side fetching для real-time, и всегда думать о trade-offs между свежестью данных и производительностью.