Заголовки запросов

В контексте веб-разработки заголовки запросов играют ключевую роль в управлении взаимодействием клиента и сервера, особенно при работе с кэшированием. Правильная настройка заголовков позволяет оптимизировать производительность, уменьшить нагрузку на сервер и обеспечить актуальность данных. В JavaScript заголовки можно настраивать через встроенные механизмы fetch и XMLHttpRequest, а также через сервис-воркеры и промежуточные библиотеки.


Основные заголовки для управления кэшированием

Cache-Control Это основной заголовок, управляющий поведением кэша. Он может содержать несколько директив:

  • no-cache – заставляет браузер проверять у сервера актуальность ресурса перед использованием локальной копии.
  • no-store – запрещает хранение ресурса в кэше полностью.
  • max-age=<seconds> – задает максимальное время жизни ресурса в кэше. После истечения этого времени браузер обязан запросить свежую версию.
  • public и private – определяют доступность кэширования: public разрешает кэширование всеми, private только для конкретного пользователя.

Пример использования в fetch:

fetch('/api/data', {
  headers: {
    'Cache-Control': 'no-cache'
  }
})
.then(response => response.json())
.then(data => console.log(data));

ETag Заголовок ETag используется для проверки того, изменился ли ресурс на сервере. Сервер присваивает уникальный идентификатор каждому состоянию ресурса. При последующих запросах клиент может отправить этот идентификатор в заголовке If-None-Match. Если ресурс не изменился, сервер вернет статус 304 Not Modified, экономя трафик.

Пример использования:

fetch('/api/data', {
  headers: {
    'If-None-Match': '"1234567890"'
  }
})
.then(response => {
  if (response.status === 304) {
    console.log('Используем кэшированную версию');
  } else {
    return response.json();
  }
})
.then(data => console.log(data));

Last-Modified / If-Modified-Since Last-Modified указывает время последнего изменения ресурса на сервере. Клиент может использовать заголовок If-Modified-Since для запроса только новых данных. Сервер возвращает 304 Not Modified, если ресурс не изменился.

Пример:

fetch('/api/data', {
  headers: {
    'If-Modified-Since': 'Wed, 21 Oct 2025 07:28:00 GMT'
  }
})
.then(response => {
  if (response.status === 304) {
    console.log('Данные не изменились');
  } else {
    return response.json();
  }
})
.then(data => console.log(data));

Управление кэшированием на стороне клиента

Service Workers Сервис-воркеры позволяют реализовать сложную стратегию кэширования. Они перехватывают сетевые запросы и могут отдавать кэшированные ресурсы, проверять их актуальность или обновлять кэш асинхронно.

Пример простого service worker:

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(cachedResponse => {
        if (cachedResponse) {
          return cachedResponse;
        }
        return fetch(event.request).then(networkResponse => {
          return caches.open('dynamic-cache').then(cache => {
            cache.put(event.request, networkResponse.clone());
            return networkResponse;
          });
        });
      })
  );
});

Stale-while-revalidate Стратегия, позволяющая сразу отдавать старую версию ресурса из кэша, параллельно запрашивая свежую у сервера. После получения обновленной версии кэш обновляется.


Практические рекомендации

  1. Комбинация Cache-Control и ETag обеспечивает оптимальный баланс между производительностью и актуальностью данных.
  2. Для динамических данных лучше использовать no-cache или max-age=0 с ETag/Last-Modified.
  3. Для статических ресурсов (скрипты, стили, изображения) допустимо долгое кэширование (max-age=31536000) с уникальными именами файлов для обновления.
  4. Отслеживание изменений через ETag или Last-Modified позволяет минимизировать сетевой трафик и ускорить работу приложения.

Особенности работы в браузере

  • Разные браузеры могут по-разному интерпретировать Cache-Control, особенно при сочетании нескольких директив.
  • Прокси-серверы и CDN также могут влиять на кэширование, поэтому важно учитывать заголовки Vary и Pragma.
  • Метод fetch поддерживает объект Request, где можно задавать отдельные политики кэширования через свойство cache (default, no-store, reload, no-cache, force-cache, only-if-cached).

Пример:

fetch('/api/data', { cache: 'reload' })
  .then(response => response.json())
  .then(data => console.log(data));

Заключение по заголовкам

Грамотное использование заголовков запросов позволяет контролировать процесс кэширования на всех уровнях: от браузера до сервера и промежуточных прокси. Комбинация директив Cache-Control, ETag, Last-Modified и современных подходов вроде сервис-воркеров обеспечивает высокую производительность и актуальность данных в приложениях на JavaScript.