INTEGRITY Документация

Конфигурация

Кеширование Workers настраивается для каждого Worker отдельно, в файле конфигурации Wrangler. При включении кеширование применяется к каждому fetch() вызов: запросы конечных пользователей, service binding fetch() вызовы, а также loopback fetch() вызовов между точками входа через ctx.exports : если только вы отключить его для конкретной точки входа. Пользовательский Методы RPC обходят кеш.

Это кэш вашего Worker : настраивается через код вашего Worker и файл Wrangler. Worker полностью управляет своим кешем через:

Это и есть весь набор доступных настроек.

Включите кэширование

Добавьте cache блок в конфигурацию Wrangler:

{
	"name": "my-worker",
	"main": "src/index.ts",
	// Set this to today's date
	"compatibility_date": "2026-08-28",
	"cache": {
		"enabled": true,
	},
}
name = "my-worker"
main = "src/index.ts"
# Set this to today's date
compatibility_date = "2026-08-28"

[cache]
enabled = true

Настройка cache.enabled к true приводит к тому, что Cloudflare проверяет кэш перед вызовом вашего Worker при каждом HTTP запросе. Это поведение по умолчанию для каждой точки входа; вы можете переопределить его для конкретной точки входа с помощью exports.

cache блок принимает два поля: enabled (обязательно) и cross_version_cache (необязательно). Любые другие поля зарезервированы для использования в будущем и могут вызывать ошибки валидации в будущих версиях Wrangler.

Отключить кеширование

Чтобы отключить кеширование, задайте cache.enabled к false (или удалите cache блок) и разверните заново:

{
	"name": "my-worker",
	"main": "src/index.ts",
	// Set this to today's date
	"compatibility_date": "2026-08-28",
	"cache": {
		"enabled": false,
	},
}
name = "my-worker"
main = "src/index.ts"
# Set this to today's date
compatibility_date = "2026-08-28"

[cache]
enabled = false

Отключение кеширования не удаляет уже закешированные ответы: это лишь останавливает обращение Cloudflare к кешу и его заполнение при последующих запросах. Если вы позже снова включите кеширование, записи, у которых ещё не истёк TTL, снова станут доступны. Если нужно, чтобы кешированные ответы перестали отдаваться немедленно, очистить кэш после отключения.

Кэширование для каждой точки входа

cache.enabled задает значение по умолчанию для всего Worker, но Worker может предоставлять несколько entrypoints : экспорт по умолчанию и любое количество именованных WorkerEntrypoint классы, и для каждого из них можно независимо включать или отключать кэширование. Используйте exports map с ключами по имени точки входа и "default" ссылаясь на экспорт по умолчанию:

{
	"name": "my-worker",
	"main": "src/index.ts",
	// Set this to today's date
	"compatibility_date": "2026-08-28",
	"cache": {
		"enabled": true,
	},
	"exports": {
		// Opt the default entrypoint out of caching.
		"default": { "type": "worker", "cache": { "enabled": false } },
		// Keep caching on for the Admin entrypoint.
		"Admin": { "type": "worker", "cache": { "enabled": true } },
	},
}
name = "my-worker"
main = "src/index.ts"
# Set this to today's date
compatibility_date = "2026-08-28"

[cache]
enabled = true

[exports.default]
type = "worker"

  [exports.default.cache]
  enabled = false

[exports.Admin]
type = "worker"

  [exports.Admin.cache]
  enabled = true

Размер каждой записи составляет { "type": "worker", "cache": { "enabled": <boolean> } }. Отдельный для каждого entrypoint cache.enabled переопределяет параметр верхнего уровня cache.enabled для этой точки входа; точки входа, которые вы не укажете, наследуют значение верхнего уровня. Вы также можете включить кеширование для одной точки входа без cache блок, указав только эту точку входа.

Это позволяет вам включать и отключать отдельные точки входа без изменения кода вашего Worker:

Версионированные развёртывания

cache конфигурация входит в состав версии вашего Worker:

Кеширование между версиями

По умолчанию Версия Worker входит в состав ключа кеша. У каждой развёрнутой версии свой изолированный кэш, поэтому новое развёртывание начинается с пустого кэша и никогда не отдаёт ответы, записанные предыдущей версией. Такое поведение принято по умолчанию, поскольку его проще всего понять: новое развёртывание вступает в силу немедленно, и вы никогда не получаете ответ, созданный вытесненной версией.

Компромисс заключается в том, что коэффициент попаданий в кеш сбрасывается при каждом развёртывании. Поскольку новая версия не может использовать закешированные ответы предыдущей версии, первые запросы после развёртывания оказываются промахами, пока кеш новой версии не наполнится. Это самая частая причина падения cache hit rate у Worker сразу после развёртывания.

Если вы хотите максимизировать долю попаданий в кэш и готовы мириться с более медленным раскатыванием изменений, влияющих на кэш, укажите cross_version_cache к true. Закешированные ответы затем становятся общими для всех версий: ответ, записанный одной версией, может быть отдан более поздней версией, пока не истёк его TTL:

{
	"name": "my-worker",
	"main": "src/index.ts",
	// Set this to today's date
	"compatibility_date": "2026-08-28",
	"cache": {
		"enabled": true,
		"cross_version_cache": true,
	},
}
name = "my-worker"
main = "src/index.ts"
# Set this to today's date
compatibility_date = "2026-08-28"

[cache]
enabled = true
cross_version_cache = true

Опытным пользователям, которые часто деплоят и чьи ответы почти не меняются между деплоями, стоит рассмотреть включение cross_version_cache : это позволяет не терять прогретый кеш при каждом деплое. Плата за это в том, что деплой больше не сбрасывает кеш: после изменения, которое меняет содержимое ответа, старые закешированные ответы продолжают отдаваться, пока не истечёт их срок действия или пока вы очистка их, а во время постепенное развёртывание обе версии используют общий кеш. Если развертывание должно вступить в силу немедленно с cross_version_cache включено, очистите кеш после деплоя либо помечайте ответы версией: см. Аннулирование кэша между развёртываниями.

cross_version_cache действует только при включённом кешировании. Он применяется ко всем точкам входа с включённым кешем.

Конфигурация для конкретного окружения

cache блок можно задать на верхнем уровне и переопределить для каждого окружение. Типичный подход: включать кэширование в production, когда вы уверены в его безопасности, и оставлять staging без кэша для упрощения отладки:

{
	"name": "my-worker",
	"main": "src/index.ts",
	// Set this to today's date
	"compatibility_date": "2026-08-28",
	"cache": {
		"enabled": false,
	},
	"env": {
		"production": {
			"cache": {
				"enabled": true,
			},
		},
	},
}
name = "my-worker"
main = "src/index.ts"
# Set this to today's date
compatibility_date = "2026-08-28"

[cache]
enabled = false

[env.production.cache]
enabled = true

Семантика Cache-Control

При включенном кешировании ваш Worker выступает источником (origin) для кеша Cloudflare. Стандартные HTTP Cache-Control директивы в ответе, который возвращает ваш Worker, определяют, кеширует ли Cloudflare этот ответ и на какой срок. Полный список директив и их взаимодействие см. в Cache-Control.

Настройте окно свежести с помощью max-age

Используйте max-age чтобы управлять тем, как долго ответ считается актуальным:

src/index.js
export default {
	async fetch(request) {
		const body = await renderPage(request);

		return new Response(body, {
			headers: {
				"Content-Type": "text/html",
				// Cached for 1 hour at Cloudflare's edge and in the browser.
				"Cache-Control": "public, max-age=3600",
			},
		});
	},
};

// Replace with your own rendering logic.
async function renderPage(request) {
	return `<!doctype html><title>Home</title><h1>Hello</h1>`;
}
src/index.ts
export default {
	async fetch(request): Promise<Response> {
		const body = await renderPage(request);

		return new Response(body, {
			headers: {
				"Content-Type": "text/html",
				// Cached for 1 hour at Cloudflare's edge and in the browser.
				"Cache-Control": "public, max-age=3600",
			},
		});
	},
} satisfies ExportedHandler;

// Replace with your own rendering logic.
async function renderPage(request: Request): Promise<string> {
	return `<!doctype html><title>Home</title><h1>Hello</h1>`;
}

Если браузерам и edge-серверам нужно кешировать данные на разное время, используйте cdn-cache-control (или cloudflare-cdn-cache-control) для директивы, действующей только на edge, и сохраните Cache-Control для того, что видят браузеры. См. Приоритет заголовков ниже.

Используйте stale-while-revalidate для обновлений с низкой задержкой

Когда кэшированный ответ устаревает, stale-while-revalidate позволяет Cloudflare сразу возвращать устаревший ответ и обновлять его в фоновом режиме:

src/index.js
export default {
	async fetch(request) {
		const data = { timestamp: Date.now() };

		return new Response(JSON.stringify(data), {
			headers: {
				"Content-Type": "application/json",
				// Fresh for 10 minutes; may be served stale for up to 1 minute
				// while a background revalidation runs.
				"Cache-Control": "public, max-age=600, stale-while-revalidate=60",
			},
		});
	},
};
src/index.ts
export default {
	async fetch(request): Promise<Response> {
		const data = { timestamp: Date.now() };

		return new Response(JSON.stringify(data), {
			headers: {
				"Content-Type": "application/json",
				// Fresh for 10 minutes; may be served stale for up to 1 minute
				// while a background revalidation runs.
				"Cache-Control": "public, max-age=600, stale-while-revalidate=60",
			},
		});
	},
} satisfies ExportedHandler;

Выберите значения TTL и stale-while-revalidate

Высокий процент попаданий в кеш и высокая свежесть данных противоречат друг другу. Фоновая ревалидация скрывает задержку обновления кеша, однако Worker всё равно запускается при каждой ревалидации: это не бесплатно.

Два распространённых паттерна:

Отдавайте устаревший контент при ошибке с stale-if-error

stale-if-error позволяет Cloudflare возвращать ранее закешированный ответ, если Worker завершается с ошибкой при обновлении просроченной записи кеша: например, если он выбрасывает исключение, превышает время ожидания или возвращает 5xx ответ. Это защищает клиентов от временных сбоев Worker.

"Cache-Control": "public, max-age=600, stale-if-error=86400",

Когда Worker формирует новый ответ, stale-if-error не действует. Если Worker завершается с ошибкой при обновлении устаревшей записи, Cloudflare отдает последний успешный кэшированный ответ (с Cf-Cache-Status: STALE) на срок до stale-if-error окна. Настоящий промах кэша (при отсутствии предыдущей записи) не может воспользоваться stale-if-error потому что отдавать устаревшие данные нечего: в этом случае ошибки Worker передаются клиентам напрямую.

Приоритет заголовков

Если присутствует несколько заголовков кэша, побеждает наиболее специфичный:

  1. cloudflare-cdn-cache-control : специфично для Cloudflare, имеет наивысший приоритет. Обрабатывается Cloudflare и удаляется из ответа перед отправкой клиентам.
  2. cdn-cache-control : стандартный заголовок для директив, предназначенных только для CDN. Cloudflare учитывает его и передаёт нижестоящим CDN.
  3. Cache-Control : стандартный HTTP-заголовок. Cloudflare учитывает его и передаёт клиентам.

Используйте cloudflare-cdn-cache-control когда нужен более длинный edge TTL, чем тот, что вы показываете браузерам, не передавая эту директиву дальше по цепочке.

Переопределить Cache-Control от вызывающего Worker

Обычно вызываемая сторона сама определяет, как кешировать ответы, задавая Cache-Control для них. Когда одна точка входа вызывает другую кешируемую точку входа через ctx.exports loopback, вызов точка входа может вместо этого предоставлять Cache-Control директиву для этого вызова, задав cf.cacheControl к запросу.

Здесь Backend точка входа не возвращает Cache-Control собственную; точка входа по умолчанию определяет политику кеширования при вызове Backend через ctx.exports:

src/index.js
import { WorkerEntrypoint } from "cloudflare:workers";

// Cached entrypoint. It does not set Cache-Control itself.
export class Backend extends WorkerEntrypoint {
	async fetch(request) {
		return new Response("Hello from the backend", {
			headers: { "Content-Type": "text/html" },
		});
	}
}

// Gateway entrypoint. Caches the Backend's response for this call for
// 5 minutes, without the Backend needing to set Cache-Control itself.
export default {
	async fetch(request, env, ctx) {
		return ctx.exports.Backend.fetch(request, {
			cf: { cacheControl: "public, max-age=300" },
		});
	},
};
src/index.ts
import { WorkerEntrypoint } from "cloudflare:workers";

// Cached entrypoint. It does not set Cache-Control itself.
export class Backend extends WorkerEntrypoint<Env> {
	async fetch(request: Request): Promise<Response> {
		return new Response("Hello from the backend", {
			headers: { "Content-Type": "text/html" },
		});
	}
}

// Gateway entrypoint. Caches the Backend's response for this call for
// 5 minutes, without the Backend needing to set Cache-Control itself.
export default {
	async fetch(request, env, ctx): Promise<Response> {
		return ctx.exports.Backend.fetch(request, {
			cf: { cacheControl: "public, max-age=300" },
		});
	},
} satisfies ExportedHandler<Env>;

Cloudflare рассматривает cf.cacheControl как доверенный Cache-Control директиву для кеширования ответа вызываемой стороны в рамках этого вызова. Значением служит стандартный Cache-Control строка и соответствует та же семантика директивы описанного на этой странице: max-age, stale-while-revalidate, no-store, и так далее. Это позволяет вызывающей точке входа определять, как кэшируются ответы кэшируемой точки входа, не изменяя код самой точки входа.

Подобно пользовательские ключи кеша, cf.cacheControl учитывается только для вызовов в пределах вашего аккаунта. Cloudflare отбрасывает cf объект при каждом запросе, который пересекает границу аккаунта, поэтому вызывающая сторона в одном аккаунте не может изменить способ кеширования ответов Worker в другом аккаунте. Эта директива также не действует на запросы конечных пользователей (eyeball requests), поскольку cf объект во входящем запросе заполняется Cloudflare, а не клиентом.

Заголовки ответа

Cf-Cache-Status

Каждый ответ содержит Cf-Cache-Status заголовок, указывающий, что произошло с этим запросом. Чаще всего вы будете видеть значения HIT, MISS, EXPIRED, REVALIDATED, UPDATING, STALE, а также BYPASS. Полный список значений и их описание см. в Кеширование ответов Cloudflare.

Cache-Tag

Cache-Tag заголовок ответа прикрепляет теги к кешированному ответу, чтобы вы могли позже очистить кеш пакетно. Cloudflare считывает этот заголовок и удаляет его до того, как ответ дойдет до клиента.

src/index.js
export default {
	async fetch(request) {
		const html = `<!doctype html><title>Post</title>`;

		return new Response(html, {
			headers: {
				"Content-Type": "text/html",
				"Cache-Control": "public, max-age=3600",
				"Cache-Tag": "blog,posts,post-123",
			},
		});
	},
};
src/index.ts
export default {
	async fetch(request): Promise<Response> {
		const html = `<!doctype html><title>Post</title>`;

		return new Response(html, {
			headers: {
				"Content-Type": "text/html",
				"Cache-Control": "public, max-age=3600",
				"Cache-Tag": "blog,posts,post-123",
			},
		});
	},
} satisfies ExportedHandler;

Cache-Tag заголовка представляет собой список тегов, разделённых запятыми. Действуют те же ограничения, что и для кеша зоны, подробнее см. Лимиты Cache Tag для полного списка. Наиболее распространённые ограничения, которые следует учитывать:

Недопустимые теги (слишком длинные, содержащие пробелы или символы не из набора ASCII) при кэшировании молча отбрасываются. Ответ всё равно кэшируется с оставшимися допустимыми тегами, но узнать, какие теги были отброшены, невозможно. Если это важно, проверяйте теги в Worker перед тем, как их возвращать.

Условия автоматического обхода кеша

Кеширование Workers наследует стандартные правила обхода кеша. Наиболее частые причины:

Если применимо любое из перечисленного, Cf-Cache-Status это BYPASS и ваш Worker выполняется при каждом запросе.

Коды состояния, которые никогда не кэшируются

Некоторые коды состояния никогда не сохраняются, даже при явном Cache-Control директивы:

Range запросы

Workers Caching обслуживает Range запросы из закешированного полного ответа: вашему Worker не придётся самостоятельно реализовывать нарезку по диапазонам байтов (byte-range slicing).

Когда клиент отправляет Range запрос, Cloudflare удаляет Range заголовок перед вызовом вашего Worker и запрашивает у вашего Worker полное тело. Ваш Worker возвращает обычный 200 ответ с Cache-Control заголовка (как и для любого другого запроса), Cloudflare сохраняет этот полный ответ, а затем вырезает запрошенный диапазон байт и возвращает его клиенту как 206 Partial Content ответ (или 416 Range Not Satisfiable если диапазон недействителен). Последующие Range запросы к одному и тому же URL полностью обслуживаются из закешированной записи: ваш Worker не вызывается, и Cf-Cache-Status это HIT.

Например, GET с Range: bytes=0-9 при холодном кеше дает MISS на входе (ваш Worker выполняется и возвращает полное тело), а затем возвращает 206 с первыми 10 байтами. Последующий GET Range: bytes=10-19 для одного и того же URL является HIT и возвращает эти 10 байт из кеша, не вызывая ваш Worker.

Если ваш Worker возвращает 206 собственный ответ, например, потому что вы реализовали Range обработку внутри Worker, Cloudflare считает такой ответ некэшируемым и не сохраняет его. Верните полный 200 и позвольте Workers Caching самостоятельно обрабатывать разбиение диапазонов.

Vary

Когда ваш Worker возвращает Vary заголовок ответа, Cloudflare сохраняет отдельный кешированный вариант для каждой уникальной комбинации значений перечисленных заголовков запроса и возвращает только тот вариант, чьи сохраненные значения совпадают со значениями входящего запроса. Это реализует RFC 9110 и вычисление cache-key в RFC 9111. Вводную информацию с примерами кода см. в Согласование содержимого с использованием Vary.

Как Vary обрабатывается для Workers Caching:

Accept-Encoding и Content-Encoding

Worker сам управляет согласованием содержимого. Что бы ни Content-Encoding ваш Worker устанавливает в ответе, Cloudflare сохраняет и отдаёт в последующих запросах.

Если вашему Worker нужно возвращать разным клиентам разные кодировки, у вас есть два варианта: