INTEGRITY Dokumentace

Mezipaměť Workers

Workers Cache umožňuje Cloudflare vracet cachované HTTP odpovědi z vašeho Workeru bez spuštění jeho kódu. Když příchozí požadavek odpovídá cachované odpovědi, Cloudflare ji doručí přímo z edge cache, čímž snižuje latenci a spotřebu CPU Workers.

Ukládání do mezipaměti funguje pro jakýkoli fetch() volání Workeru: požadavky od uživatelů (requesty z prohlížečů a API klientů), požadavky odeslané přes service bindings, a zpětnou smyčku (loopback) fetch() volání mezi entrypointy přes ctx.exports. Cachování řídíte pomocí standardních HTTP Cache-Control direktivy ve vašich odpovědích.

Cache vašeho Workeru

Workers Cache je cache vašeho Workeru. Vlastní ho váš Worker, provozuje ho váš Worker a je soukromý pouze pro váš Worker.

Worker je entita bez zóny: lze ho navázat na libovolný počet zóny, spusťte na workers.dev, nebo být vyvolán zcela prostřednictvím service bindings, aniž by se kdy dotkl zóny. Cache se řídí Workerem, nikoli zónou, takže:

Worker je konfigurační rozhraní

Worker je již nekonečně přizpůsobitelné. Můžete měnit těla odpovědí, přepisovat hlavičky, větvit podle libovolného atributu požadavku, volat jiné Workery prostřednictvím service bindings nebo ctx.exports, a skládat logiku napříč celým systémem.

Workers Caching na tom staví. Místo zavedení samostatné konfigurační vrstvy pro chování ukládání do mezipaměti umožňuje, aby váš Worker tento záměr vyjádřil přímo, a to prostřednictvím Cache-Control hlaviček, které vrací, se ctx.props přijímá, i programové purge, které vydává. Cokoli, co chcete ohledně cachování nakonfigurovat, můžete nakonfigurovat v kódu:

Worker, který jste už napsali, je konfigurační mechanismus. Workers Caching běží před ním a respektuje veškeré hlavičky, které Worker vrátí.

Kdy mezipaměť pomáhá

Ukládání do mezipaměti je vhodné pro Workers, které:

Ukládání do mezipaměti není užitečné pro odpovědi specifické pro uživatele, které se mění při každém požadavku, ani pro neidempotentní operace (POST, PUT, DELETE), nebo odpovědi, které je nutné pokaždé vypočítat znovu.

Jak to funguje

Když je cachování zapnuté, Cloudflare zkontroluje cache ještě před spuštěním vašeho Workeru. Při zásahu (hit) se vrátí rovnou odpověď z cache. Při zmeškání (miss) se Worker spustí, a pokud je odpověď podle svých Cache-Control hlavičku, Cloudflare ji uloží pro příští požadavek.

flowchart LR
    accTitle: Cache before a Worker request flow
    accDescr: Request arrives at Cloudflare, cache is consulted before Worker execution.

    Request["Request"] --> Cache{"Cache"}
    Cache -- Hit --> Response["Cached response returned"]
    Cache -- Miss --> Worker["Worker runs"]
    Worker --> Store["Response stored in cache"]
    Store --> Response2["Response returned"]

Tiered cache

Workers Caching je ve výchozím nastavení vrstvené. Pro váš Worker Cloudflare provozuje dvě vrstvy cache:

Požadavek se poskytne z nižší vrstvy, pokud tam dojde ke shodě (hit). Pokud dojde k neshodě (miss), nižší vrstva se zeptá vyšší vrstvy. Pokud dojde k neshodě i ve vyšší vrstvě, teprve poté se spustí váš Worker a vygeneruje odpověď, která se následně uloží do obě vrstvy na cestě zpět, takže z toho těží i následné požadavky z libovolného datového centra.

flowchart LR
    accTitle: Tiered cache for Workers
    accDescr: A request hits the lower-tier cache first, then the upper-tier cache, then the Worker.

    Request["Request"] --> Lower{"Lower-tier cache<br/>(near eyeball)"}
    Lower -- Hit --> Response["Cached response returned"]
    Lower -- Miss --> Upper{"Upper-tier cache"}
    Upper -- Hit --> Lower
    Upper -- Miss --> Worker["Worker runs"]
    Worker --> Upper

Jde o stejnou topologii, na které běží Tiered Cache pro zóny, aplikované na váš Worker automaticky. Nekonfigurujete ji a tiering běží bez ohledu na to, zda váš Worker používá Smart Placement.

Proč na tom záleží: první požadavek pro daný klíč mezipaměti kdekoli na světě naplní horní vrstvu. Každý další požadavek z libovolného datového centra Cloudflare pak lze obsloužit z horní vrstvy bez spuštění vašeho Workeru, a to i v případě, že spodní vrstva v dané lokalitě daný požadavek ještě nikdy neviděla. Poměr úspěšnosti mezipaměti je tak podstatně vyšší než u jediné ploché vrstvy mezipaměti.

Slučování požadavků

Když do datacentra Cloudflare dorazí současně mnoho požadavků se stejným klíčem mezipaměti a odpověď ještě není v mezipaměti uložena, Cloudflare spustí váš Worker jednou a výslednou odpověď poskytne všem čekajícím požadavkům. Jde o stejný slučování požadavků mechanismus, který používá cache zóny a který se automaticky uplatňuje na Workers Caching. Čekající požadavky blokují podle klíče cache cache lock dokud první požadavek nevytvoří odpověď.

flowchart LR
    accTitle: Cache request collapsing for Workers
    accDescr: Many simultaneous requests for the same cache key produce one Worker invocation; all requests receive the same response.

    R1["Request 1"] --> Lock
    R2["Request 2"] --> Lock
    R3["Request 3"] --> Lock
    Rn["..."] --> Lock
    Lock{"Cache lock<br/>(per cache key, per data center)"}
    Lock -- "first request" --> Worker["Worker runs once"]
    Worker --> Response["Response<br/>streamed to all<br/>waiting requests"]

Proč na tom záleží: bez slučování požadavků (request collapsing) by náhlý nárůst provozu na novou URL adresu vyvolal váš Worker pro každý požadavek zvlášť, což by znásobilo účtování CPU a zátěž jakéhokoli backendu, který Worker volá. Se slučováním požadavků tento nárůst stále vyvolá jen jedno spuštění Workeru.

Několik věcí, které je třeba mít na paměti:

Toto je jeden z nejvýznamnějších rozdílů mezi Workers Caching a Cache API, the Cache API does not collapse concurrent requests, so a burst of traffic to a fresh URL invokes your Worker once per request.

Rychlý start

Tento rychlý úvod vás provede aktivací ukládání do cache, nasazením a sledováním cache v praxi.

1. Povolte cachování v konfiguraci 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

2. Vraťte z Workeru odpověď, kterou lze ukládat do mezipaměti

Použijte max-age pro řízení toho, jak dlouho Cloudflare ukládá jednotlivé odpovědi do mezipaměti:

src/index.js
export default {
	async fetch(request) {
		const body = JSON.stringify({
			timestamp: new Date().toISOString(),
			random: Math.random(),
		});

		return new Response(body, {
			headers: {
				"Content-Type": "application/json",
				// Cache for 1 hour; serve stale for up to 5 minutes while revalidating.
				"Cache-Control": "public, max-age=3600, stale-while-revalidate=300",
			},
		});
	},
};
src/index.ts
export default {
	async fetch(request): Promise<Response> {
		const body = JSON.stringify({
			timestamp: new Date().toISOString(),
			random: Math.random(),
		});

		return new Response(body, {
			headers: {
				"Content-Type": "application/json",
				// Cache for 1 hour; serve stale for up to 5 minutes while revalidating.
				"Cache-Control": "public, max-age=3600, stale-while-revalidate=300",
			},
		});
	},
} satisfies ExportedHandler;

3. Nasaďte a sledujte mezipaměť

Nasaďte svůj Worker:

npx wrangler deploy

Poté odešlete dva požadavky a podívejte se na Cf-Cache-Status hlavička odpovědi:

curl -I https://my-worker.example.workers.dev/
První požadavek: očekáváno
HTTP/2 200
cache-control: public, max-age=3600, stale-while-revalidate=300
cf-cache-status: MISS
curl -I https://my-worker.example.workers.dev/
Druhý požadavek: očekávaný
HTTP/2 200
cache-control: public, max-age=3600, stale-while-revalidate=300
cf-cache-status: HIT

Druhý požadavek obdrží odpověď z mezipaměti. timestamp a random hodnoty v těle jsou u obou požadavků identické, přestože Worker při každém spuštění generuje nové. To potvrzuje, že druhý požadavek váš Worker nespustil.

Co se ukládá do mezipaměti

Cf-Cache-Status hlavička odpovědi vám řekne, co se stalo s daným požadavkem. Nejčastěji se setkáte s hodnotami HIT, MISS, EXPIRED, REVALIDATED, UPDATING, STALE, a BYPASS. Viz Cloudflare ukládá odpovědi do cache pro úplnou sadu hodnot.

Vyjednávání obsahu pomocí Vary

Workers Caching respektuje Vary hlavičku odpovědi, jak je definována v RFC 9110 a RFC 9111. Když váš Worker vrátí Vary hlavičky Cloudflare ukládá do mezipaměti samostatnou variantu pro každou odlišnou kombinaci hodnot uvedených hlaviček požadavku a variantu z mezipaměti vrátí jen tehdy, když se hlavičky příchozího požadavku shodují s těmi, pod kterými byla varianta uložena.

Díky tomu může jedna URL ukládat do cache více reprezentací, například různá kódování, různé typy obsahu nebo různé jazyky, aniž by Worker musel ručně řešit vyjednávání obsahu (content negotiation):

src/index.js
export default {
	async fetch(request) {
		const accept = request.headers.get("Accept") ?? "";
		const wantsWebp = accept.includes("image/webp");

		const body = wantsWebp ? await fetchWebpImage() : await fetchJpegImage();

		return new Response(body, {
			headers: {
				"Content-Type": wantsWebp ? "image/webp" : "image/jpeg",
				"Cache-Control": "public, max-age=3600",
				// Cache a separate variant per distinct Accept header value.
				Vary: "Accept",
			},
		});
	},
};
src/index.ts
export default {
	async fetch(request): Promise<Response> {
		const accept = request.headers.get("Accept") ?? "";
		const wantsWebp = accept.includes("image/webp");

		const body = wantsWebp ? await fetchWebpImage() : await fetchJpegImage();

		return new Response(body, {
			headers: {
				"Content-Type": wantsWebp ? "image/webp" : "image/jpeg",
				"Cache-Control": "public, max-age=3600",
				// Cache a separate variant per distinct Accept header value.
				Vary: "Accept",
			},
		});
	},
} satisfies ExportedHandler;

Poznámky:

Ukládání do mezipaměti mezi Workers

Když jeden Worker volá jiný přes service binding, volané strany se nahlédne do cache. Pokud má callee zapnuté ukládání do cache a existuje odpovídající uložená odpověď, caller ji obdrží, aniž by se callee vůbec zavolal.

flowchart LR
    accTitle: Cache between Workers
    accDescr: Worker A calls Worker B; Worker B's cache is consulted before Worker B runs.

    Request["Request"] --> WorkerA["Worker A"]
    WorkerA --> CacheB{"Worker B's cache"}
    CacheB -- Hit --> WorkerA
    CacheB -- Miss --> WorkerB["Worker B"]
    WorkerB --> CacheB

Klíč cache pro volání přes service binding zahrnuje volajícího ctx.props, takže různí volající s odlišným kontextem autorizace se ukládají do cache odděleně. Podrobnosti naleznete v Cache keys.

U volání v rámci stejného účtu může volající Worker přizpůsobit cachování volaného i pro jednotlivý požadavek, a to nastavením cf.cacheKey pro přepsání klíče mezipaměti nebo cf.cacheControl pro poskytnutí Cache-Control direktiva.

Ukládání odpovědí Durable Object do mezipaměti

Durable Objects se nikdy neukládají přímo do mezipaměti pomocí Workers Caching. Jelikož ale Workers Caching běží před libovolným entrypointem Workeru, můžete HTTP odpovědi Durable Object ukládat do mezipaměti tak, že Durable Object obalíte pojmenovaný entrypoint Workeru a ukládání vstupního bodu do mezipaměti.

Vstupní bod obalu předává požadavek do Durable Object a nastavuje Cache-Control na odpovědi, kterou vrací. Protože Workers Caching je umístěno před entrypointem, další požadavky se obsluhují z mezipaměti, aniž by znovu vstupovaly do Durable Object.

Výchozím vstupním bodem je zde gateway, který by měl běžet při každém požadavku, proto na něm mezipaměť vypněte a zapněte ji na CachedCounter (viz Ukládání do mezipaměti pro jednotlivé entrypointy):

{
	"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", "cache": { "enabled": false } },
		"CachedCounter": { "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.CachedCounter]
type = "worker"

  [exports.CachedCounter.cache]
  enabled = true
src/index.js
import { WorkerEntrypoint } from "cloudflare:workers";

// Cached entrypoint. Requests to this entrypoint are served from cache
// when possible; on a miss, the Durable Object is invoked and its
// response is stored.
export class CachedCounter extends WorkerEntrypoint {
	async fetch(request) {
		const id = this.env.COUNTER.idFromName("global");
		const stub = this.env.COUNTER.get(id);
		const response = await stub.fetch(request);

		// Attach cache headers. Clone into a new Response so the headers
		// are mutable.
		return new Response(response.body, {
			status: response.status,
			headers: {
				...Object.fromEntries(response.headers),
				"Cache-Control": "public, max-age=30",
			},
		});
	}
}

// Default entrypoint. Delegates to the cached entrypoint via ctx.exports,
// which routes through the cache.
export default {
	async fetch(request, env, ctx) {
		return ctx.exports.CachedCounter.fetch(request);
	},
};
src/index.ts
import { WorkerEntrypoint } from "cloudflare:workers";

interface Env {
	COUNTER: DurableObjectNamespace;
}

// Cached entrypoint. Requests to this entrypoint are served from cache
// when possible; on a miss, the Durable Object is invoked and its
// response is stored.
export class CachedCounter extends WorkerEntrypoint<Env> {
	async fetch(request: Request): Promise<Response> {
		const id = this.env.COUNTER.idFromName("global");
		const stub = this.env.COUNTER.get(id);
		const response = await stub.fetch(request);

		// Attach cache headers. Clone into a new Response so the headers
		// are mutable.
		return new Response(response.body, {
			status: response.status,
			headers: {
				...Object.fromEntries(response.headers),
				"Cache-Control": "public, max-age=30",
			},
		});
	}
}

// Default entrypoint. Delegates to the cached entrypoint via ctx.exports,
// which routes through the cache.
export default {
	async fetch(request, env, ctx): Promise<Response> {
		return ctx.exports.CachedCounter.fetch(request);
	},
} satisfies ExportedHandler<Env>;

Další vzory kombinující gateway entrypoint s cachovanými vnitřními entrypointy najdete v Příklady.

Smart placement a cache

Smart Placement přesouvá kde běží váš Worker při svém běhu, obvykle blíže pomalému origin serveru nebo databázi. Cache tím nepřesouvá. Workers Caching má vždy nižší úroveň blízko eyeballu a vyšší úroveň agregující síť, přesně jak je popsáno v Tiered cache výše, bez ohledu na to, zda je Smart Placement povoleno.

Cache se vždy zkontroluje dříve, než se zváží Smart Placement. Konkrétně:

Je důležité, že horní vrstva a cílová lokalita Smart Placement jsou nezávislé lokality. Horní vrstvu (upper tier) volí Cloudflare tak, aby agregovala plnění cache napříč sítí, zatímco cíl Smart Placement je zvolen tak, aby minimalizoval latenci mezi vaším Workerem a jeho backendem. Zpravidla se nenachází ve stejném datacentru.

flowchart LR
    accTitle: Tiered cache with Smart Placement across three locations
    accDescr: The eyeball, the upper-tier cache, and the Smart Placement target are three independent locations. Requests traverse them in order on a full cache miss.

    subgraph EyeballColo["Data center near eyeball"]
        Request["Request"] --> Lower{"Lower-tier cache"}
    end

    subgraph UpperColo["Upper-tier data center"]
        Upper{"Upper-tier cache"}
    end

    subgraph PlacedColo["Smart Placement target"]
        Placed["Worker runs"]
        Origin["Origin / backend"]
        Placed <--> Origin
    end

    Lower -- Hit --> Response["Response"]
    Lower -- Miss --> Upper
    Upper -- Hit --> Lower
    Upper -- Miss --> Placed
    Placed --> Upper

Při úplném zásahu mimo cache tedy požadavek prochází třemi místy: datovým centrem nižší úrovně poblíž uživatele, datovým centrem vyšší úrovně a cílem Smart Placement. Vrstvy cache tyto náklady pohlcují, takže pomalá cesta k cíli Smart Placement se pro celou síť zaplatí jen jednou: vyšší vrstva chrání cíl Smart Placement před každým výpadkem nižší vrstvy.

Vymazávání mezipaměti

Váš Worker může kdykoli invalidovat vlastní cache pomocí ctx.cache.purge(). Tagy jsou nejflexibilnější mechanismus: odpovědi otagujte pomocí Cache-Tag při jejich vracení a tyto tagy později purgovat:

src/index.js
export default {
	async fetch(request, env, ctx) {
		await ctx.cache.purge({ tags: ["blog-posts"] });
		return new Response("Purged", { status: 200 });
	},
};
src/index.ts
export default {
	async fetch(request, env, ctx): Promise<Response> {
		await ctx.cache.purge({ tags: ["blog-posts"] });
		return new Response("Purged", { status: 200 });
	},
} satisfies ExportedHandler;

Můžete také import cache z cloudflare:workers a volejte cache.purge({...}) pokud nemáte ctx v rozsahu, například z pomocného modulu. Všechny režimy a vzory purge najdete v Vymazávání mezipaměti.

Ceny

Workers Cache nemá samostatné ceny. Po zapnutí Workers Cache se všechny požadavky na váš Worker účtují podle standardní Míra požadavků Workers, the same per-request rate as any other request to your Worker, whether the response comes from cache or from your Worker. There is no charge beyond the standard request rate. Čas CPU se účtuje pouze v době, kdy Worker běží : cache hity nespotřebovávají CPU time.

Typ požadavku Poplatek za požadavek Účtování času CPU
Cache HIT (Worker se nespustí) Sazba Standard Neúčtuje se
Cache MISS (Worker se spustí) Sazba Standard Účtováno
Cache BYPASS (Worker se spustí) Sazba Standard Účtováno
Požadavek na statický prostředek Sazba Standard Neúčtuje se
Worker-to-worker vyvolání Sazba Standard Účtováno, pokud Worker běží

Příklad najdete v Příklad ceny: Worker s ukládáním do mezipaměti.

Další kroky