HTTP заголовки и управление кешем

Кеширование в API часто контролируется с помощью HTTP-заголовков, которые позволяют серверу и клиенту обмениваться информацией о состоянии и сроке действия данных. Наиболее часто используемые заголовки для управления кешированием включают Cache-Control, ETag, и Last-Modified. Разберем каждый из них подробно.

Использование заголовков Cache-Control, ETag, и Last-Modified

Cache-Control

Заголовок Cache-Control управляет основными параметрами кеширования, включая время жизни, доступность и применимость кеша. Он может быть настроен как на стороне сервера, так и на стороне клиента. Ключевые директивы включают:

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

ETag

Заголовок ETag (Entity Tag) используется для уникальной идентификации версии ресурса. Когда ресурс изменяется, его ETag также изменяется, что позволяет эффективно управлять кешированием и проверкой изменений. Примеры:

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

Last-Modified

Заголовок Last-Modified указывает на дату и время последнего изменения ресурса. Он работает в паре с заголовком If-Modified-Since, который клиент отправляет в запросе, чтобы проверить актуальность кешированных данных. Примеры:

  • Last-Modified: Tue, 20 May 2023 10:00:00 GMT: указывает время последнего изменения ресурса.
  • Клиент отправляет If-Modified-Since: Tue, 20 May 2023 10:00:00 GMT в запросе.
  • Если ресурс не изменился с указанного времени, сервер отвечает статусом 304 Not Modified.

Настройка предполагаемого (heuristic) кеширования

Предполагаемое кеширование используется, когда сервер не предоставляет явные директивы кеширования. В этом случае клиент или прокси-кеш может применять эвристические методы для определения срока жизни кеша на основе времени последней модификации и времени получения ресурса.

Основные подходы:

  • Последнее изменение и получение: вычисление времени жизни кеша как доли от времени, прошедшего с момента последнего изменения ресурса до времени получения ответа.
  • Пользовательские алгоритмы: использование специфических для приложения логик, основанных на паттернах доступа и изменении данных.

Пример:

  • Время получения ресурса: 12:00.
  • Время последнего изменения ресурса: 10:00.
  • Время жизни кеша может быть определено как 1 час (половина времени между последним изменением и получением).

Проверка валидности и обновления кеша

Эффективное управление кешем требует механизма проверки валидности кешированных данных и их своевременного обновления. Основные стратегии включают:

  • Заголовки ETag и If-None-Match: при каждом запросе клиент отправляет сохраненный ETag, сервер сравнивает его с текущей версией и возвращает либо статус 304 Not Modified, либо новую версию ресурса с обновленным ETag.

  • Заголовки Last-Modified и If-Modified-Since: клиент отправляет дату последнего модифицирования, сервер сравнивает ее с текущей датой изменения ресурса и возвращает либо статус 304 Not Modified, либо обновленную версию ресурса.

  • Инвалидация кеша: активное управление кешем с использованием инструментов и библиотек для удаления устаревших данных. Например, в Redis можно устанавливать TTL для автоматической инвалидации.

  • Проактивное обновление: предварительное обновление данных в кеше на основе предположений о частоте доступа и изменении данных. Например, использование фоновых задач для периодической проверки и обновления кешированных данных.

Пример кода для реализации проверки валидности с использованием ETag в Node.js:

const express = require('express');
const app = express();

app.get('/data', (req, res) => {
  const data = getDataFromDatabase(); // Функция получения данных
  const etag = generateETag(data); // Функция генерации ETag

  if (req.headers['if-none-match'] === etag) {
    res.status(304).end(); // Возвращаем статус 304, если данные не изменились
  } else {
    res.setHeader('ETag', etag);
    res.json(data); // Возвращаем данные и новый ETag
  }
});

function generateETag(data) {
  return '"' + require('crypto').createHash('md5').update(JSON.stringify(data)).digest('hex') + '"';
}

app.listen(3000, () => console.log('Server running on port 3000'));

Эти методы и стратегии позволяют эффективно управлять кешированием в API, обеспечивая баланс между производительностью и актуальностью данных.