跳转到内容
搜索文档

清除缓存

最后更新 查看 MarkdownAgent 设置

你的 Worker 可随时使用 purge API 使其自身缓存的响应失效。当数据发生变化且提供新值比继续提供缓存响应带来的性能收益更重要时,清除缓存很有用——例如,在内容更新、用户操作或来自上游系统的 webhook 之后。

由于 Workers Caching 是你的 Worker 的缓存,清除操作的作用域限于拥有该缓存的 Worker。在 Worker 内部,清除操作进一步限定为调用 purge()入口点(entrypoint)。一个 Worker 无法访问另一个 Worker 的缓存,一个入口点无法访问另一个入口点的缓存,任何 zone 级别的清除(通过仪表板、API 或 Terraform)都不会影响 Workers Caching 的内容。

两种调用 purge 的方式

在 Worker 内部有两种等效方式触发清除:

  • ctx.cache.purge(...) — 在每个处理程序传入的执行上下文上可用。当你已在作用域内持有 ctx 时使用。
  • cache.purge(...) — 从 cloudflare:workers 导入。当你希望在不接收 ctx 的代码中调用 purge 时使用——例如,在多个处理程序间共享的工具模块,或未将执行上下文贯穿其内部的框架适配器。

两种形式调用同一 API,行为完全一致。选择在你的代码中更易读的一种即可。

src/index.jsjs
import { cache } from "cloudflare:workers";

export default {
	async fetch(request, env, ctx) {
		// Using the module import — no need to thread ctx through helper functions.
		await cache.purge({ tags: ["blog-posts"] });

		// Equivalent, using ctx directly:
		// await ctx.cache.purge({ tags: ["blog-posts"] });

		return new Response("Purged", { status: 200 });
	},
};
src/index.tsts
import { cache } from "cloudflare:workers";

export default {
	async fetch(request, env, ctx): Promise<Response> {
		// Using the module import — no need to thread ctx through helper functions.
		await cache.purge({ tags: ["blog-posts"] });

		// Equivalent, using ctx directly:
		// await ctx.cache.purge({ tags: ["blog-posts"] });

		return new Response("Purged", { status: 200 });
	},
} satisfies ExportedHandler;

本页其余示例大多使用 ctx.cache.purge(...),因为这些示例已在作用域内持有 ctx。如果你偏好导入形式,可替换为 cache.purge(...)——其余无需改动。

清除模式

purge() 可单独接受 purgeEverything: true,或接受 tagspathPrefixes 中的一个或两个:

字段 清除内容 作用域
tags 通过 Cache-Tag 标有给定值之一的每个缓存响应。 按入口点
pathPrefixes 请求路径以给定前缀之一开头的每个缓存响应。 按入口点
purgeEverything 调用 purge() 的入口点的每个缓存响应。 按入口点

purgeEverything 是互斥的——如需组合,可在单次调用中同时使用 tagspathPrefixes,但不要与 purgeEverything 一起传递其中任一参数。

三种模式均限定为调用 purge()入口点。来自 PublicAPI 的清除不会影响 AdminAPI 存储的缓存响应,即使它们共享标签名或路径前缀。若要使 Worker 的每个入口点都失效,需从每个入口点调用 purge()

返回的 promise 会解析为结果对象,你可检查以确认成功或处理失败——参见返回值

在任意会修改数据的处理程序末尾调用 ctx.cache.purge(),在写入后执行清除:

src/index.jsjs
export default {
	async fetch(request, env, ctx) {
		if (request.method === "POST") {
			const body = await request.json();

			// Mutate your data source (D1, KV, an origin, and so on), then invalidate
			// every cached response tagged for this post.
			await ctx.cache.purge({
				tags: [`post-${body.postId}`, "post-list"],
			});

			return new Response("Updated", { status: 200 });
		}

		// Handle cacheable reads here.
		return new Response("Hello", {
			headers: { "Cache-Control": "public, max-age=3600" },
		});
	},
};
src/index.tsts
export default {
	async fetch(request, env, ctx): Promise<Response> {
		if (request.method === "POST") {
			const body = await request.json<{ postId: string }>();

			// Mutate your data source (D1, KV, an origin, and so on), then invalidate
			// every cached response tagged for this post.
			await ctx.cache.purge({
				tags: [`post-${body.postId}`, "post-list"],
			});

			return new Response("Updated", { status: 200 });
		}

		// Handle cacheable reads here.
		return new Response("Hello", {
			headers: { "Cache-Control": "public, max-age=3600" },
		});
	},
} satisfies ExportedHandler;

可在单次调用中组合多个字段。例如,purge({ tags: ["blog-posts"], pathPrefixes: ["/blog/"] }) 会清除任一标签或路径前缀匹配的所有内容——字段取并集,而非交集。当一次逻辑失效会影响按多种方案标记的响应时使用。

src/index.jsjs
export default {
	async fetch(request, env, ctx) {
		// Combined call: invalidates everything tagged "blog-posts" AND
		// everything under /blog/ in a single round-trip.
		await ctx.cache.purge({
			tags: ["blog-posts"],
			pathPrefixes: ["/blog/"],
		});

		return new Response("Purged", { status: 200 });
	},
};
src/index.tsts
export default {
	async fetch(request, env, ctx): Promise<Response> {
		// Combined call: invalidates everything tagged "blog-posts" AND
		// everything under /blog/ in a single round-trip.
		await ctx.cache.purge({
			tags: ["blog-posts"],
			pathPrefixes: ["/blog/"],
		});

		return new Response("Purged", { status: 200 });
	},
} satisfies ExportedHandler;

按标签清除

标签通过 Cache-Tag 响应头附加到响应上,之后按名称清除。这是最灵活、最常用的清除方式。

写入时附加标签

src/index.jsjs
export default {
	async fetch(request) {
		const url = new URL(request.url);
		const postId = url.pathname.split("/").pop() ?? "unknown";
		const body = { id: postId, title: `Post ${postId}` };

		return new Response(JSON.stringify(body), {
			headers: {
				"Content-Type": "application/json",
				"Cache-Control": "public, max-age=3600",
				"Cache-Tag": `post,post-${postId},blog`,
			},
		});
	},
};
src/index.tsts
export default {
	async fetch(request): Promise<Response> {
		const url = new URL(request.url);
		const postId = url.pathname.split("/").pop() ?? "unknown";
		const body = { id: postId, title: `Post ${postId}` };

		return new Response(JSON.stringify(body), {
			headers: {
				"Content-Type": "application/json",
				"Cache-Control": "public, max-age=3600",
				"Cache-Tag": `post,post-${postId},blog`,
			},
		});
	},
} satisfies ExportedHandler;

Cache-Tag 头值为逗号分隔的标签列表。Cloudflare 在将响应返回给客户端之前会移除此头。

标签值必须是可打印 ASCII(无空格、无 Unicode),每个标签最长 1024 个字符,单个响应最多可携带 1000 个标签。清除时的标签匹配不区分大小写,因此 Foofoo 会清除同一组响应。无效标签在存储时会被静默丢弃——响应仍会缓存,并保留其余有效标签。完整列表请参阅缓存标签限制

触发清除

src/admin.jsjs
export default {
	async fetch(request, env, ctx) {
		const postId = new URL(request.url).searchParams.get("id");
		if (!postId) return new Response("Missing id", { status: 400 });

		await ctx.cache.purge({ tags: [`post-${postId}`] });

		return new Response("Purged", { status: 200 });
	},
};
src/admin.tsts
export default {
	async fetch(request, env, ctx): Promise<Response> {
		const postId = new URL(request.url).searchParams.get("id");
		if (!postId) return new Response("Missing id", { status: 400 });

		await ctx.cache.purge({ tags: [`post-${postId}`] });

		return new Response("Purged", { status: 200 });
	},
} satisfies ExportedHandler;

标签在入口点间的作用域

标签限定为调用 purge() 的入口点。应用于两个不同入口点响应的名为 user-42 的标签不会被单次 purge({ tags: ["user-42"] }) 调用失效——仅影响发起调用的入口点。若需在多个入口点失效同一标签,需从每个入口点调用 purge(),或将清除调用集中到一个共享入口点,由该入口点缓存你之后需要失效的所有响应。

使用层级标签

若要在一次调用中失效一组相关响应,为每个响应附加表示其所属各层级层次结构的多个标签——有时称为「软标签(soft tags)」:

src/index.jsjs
export default {
	async fetch(request) {
		const path = new URL(request.url).pathname;

		// Build a list of hierarchical tags for the current path.
		// A response at /blog/2025/02/hello gets tags for:
		//   _path:/blog/, _path:/blog/2025/, _path:/blog/2025/02/, _path:/blog/2025/02/hello
		const segments = path.split("/").filter(Boolean);
		const tags = segments.map(
			(_, i) => `_path:/${segments.slice(0, i + 1).join("/")}/`,
		);

		const body = `<!doctype html><title>${path}</title>`;

		return new Response(body, {
			headers: {
				"Content-Type": "text/html",
				"Cache-Control": "public, max-age=3600",
				"Cache-Tag": tags.join(","),
			},
		});
	},
};
src/index.tsts
export default {
	async fetch(request): Promise<Response> {
		const path = new URL(request.url).pathname;

		// Build a list of hierarchical tags for the current path.
		// A response at /blog/2025/02/hello gets tags for:
		//   _path:/blog/, _path:/blog/2025/, _path:/blog/2025/02/, _path:/blog/2025/02/hello
		const segments = path.split("/").filter(Boolean);
		const tags = segments.map(
			(_, i) => `_path:/${segments.slice(0, i + 1).join("/")}/`,
		);

		const body = `<!doctype html><title>${path}</title>`;

		return new Response(body, {
			headers: {
				"Content-Type": "text/html",
				"Cache-Control": "public, max-age=3600",
				"Cache-Tag": tags.join(","),
			},
		});
	},
} satisfies ExportedHandler;

清除标签 _path:/blog/2025/ 后,会失效 URL 以 /blog/2025/ 开头的每个缓存响应。

有关标签数量、长度和字符集的限制,请参阅缓存标签限制

按版本清除

默认情况下,Workers Caching 按 Worker 版本划分缓存,因此每次部署都会从冷缓存开始,无需按版本清除。本节仅在你启用了 cache.cross_version_cache 以在版本间共享缓存响应时适用。此时,版本 A 写入的响应在部署版本 B 后仍可能被提供,你可能希望清除特定版本写入的条目——例如,回滚之后。为此,为每个响应附加产生它的版本标签,之后清除该标签。

在 Wrangler 配置中添加版本元数据绑定(binding)

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

[cache]
enabled = true
cross_version_cache = true

[version_metadata]
binding = "CF_VERSION_METADATA"

然后将版本 ID 前置到标签中:

src/index.jsjs
export default {
	async fetch(request, env, ctx) {
		const { id: versionId } = env.CF_VERSION_METADATA;
		const postId = new URL(request.url).pathname.split("/").pop() ?? "unknown";

		return new Response(JSON.stringify({ id: postId }), {
			headers: {
				"Content-Type": "application/json",
				"Cache-Control": "public, max-age=3600",
				// Include the version ID as a tag so you can purge by version later.
				"Cache-Tag": `post,post-${postId},v:${versionId}`,
			},
		});
	},
};
src/index.tsts
interface Env {
	CF_VERSION_METADATA: WorkerVersionMetadata;
}

export default {
	async fetch(request, env, ctx): Promise<Response> {
		const { id: versionId } = env.CF_VERSION_METADATA;
		const postId = new URL(request.url).pathname.split("/").pop() ?? "unknown";

		return new Response(JSON.stringify({ id: postId }), {
			headers: {
				"Content-Type": "application/json",
				"Cache-Control": "public, max-age=3600",
				// Include the version ID as a tag so you can purge by version later.
				"Cache-Tag": `post,post-${postId},v:${versionId}`,
			},
		});
	},
} satisfies ExportedHandler<Env>;

当你希望失效特定版本写入的所有内容——例如,回滚之后——清除该版本标签:

src/admin.jsjs
export default {
	async fetch(request, env, ctx) {
		const versionId = new URL(request.url).searchParams.get("version");
		if (!versionId) return new Response("Missing version", { status: 400 });

		await ctx.cache.purge({ tags: [`v:${versionId}`] });

		return new Response("Purged", { status: 200 });
	},
};
src/admin.tsts
export default {
	async fetch(request, env, ctx): Promise<Response> {
		const versionId = new URL(request.url).searchParams.get("version");
		if (!versionId) return new Response("Missing version", { status: 400 });

		await ctx.cache.purge({ tags: [`v:${versionId}`] });

		return new Response("Purged", { status: 200 });
	},
} satisfies ExportedHandler;

按路径前缀清除

pathPrefixes 会失效请求路径以给定前缀之一开头的每个缓存响应:

src/index.jsjs
export default {
	async fetch(request, env, ctx) {
		// Invalidate everything under /blog/2025/ for the current entrypoint.
		await ctx.cache.purge({
			pathPrefixes: ["/blog/2025/"],
		});

		return new Response("Purged", { status: 200 });
	},
};
src/index.tsts
export default {
	async fetch(request, env, ctx): Promise<Response> {
		// Invalidate everything under /blog/2025/ for the current entrypoint.
		await ctx.cache.purge({
			pathPrefixes: ["/blog/2025/"],
		});

		return new Response("Purged", { status: 200 });
	},
} satisfies ExportedHandler;

pathPrefixes 中的条目是路径,而非完整 URL。前缀不得包含 scheme、主机、查询字符串或 fragment——传入类似 https://example.com/blog/ 的内容是无效输入,而非仅匹配失败的前缀。前导斜杠可选(/imagesimages 处理方式相同),但为清晰起见建议使用。

pathPrefixes 限定为发起清除调用的入口点。来自 PublicAPIpurge({ pathPrefixes: ["/blog/"] }) 不会影响 AdminAPI 存储的缓存响应,即使其路径也以 /blog/ 开头。

清除单个 URL

没有专门的「按 URL 清除」模式。若要失效单个缓存 URL,将其路径作为单元素 pathPrefixes 数组传入:

src/index.jsjs
export default {
	async fetch(request, env, ctx) {
		// Invalidate the cached response for exactly /blog/2026/hello-world.
		await ctx.cache.purge({
			pathPrefixes: ["/blog/2026/hello-world"],
		});

		return new Response("Purged", { status: 200 });
	},
};
src/index.tsts
export default {
	async fetch(request, env, ctx): Promise<Response> {
		// Invalidate the cached response for exactly /blog/2026/hello-world.
		await ctx.cache.purge({
			pathPrefixes: ["/blog/2026/hello-world"],
		});

		return new Response("Purged", { status: 200 });
	},
} satisfies ExportedHandler;

由于 pathPrefixes 按请求路径开头匹配,传入完整路径仅匹配该路径——以及恰好扩展它的路径(例如 /blog/2026/hello-world-2)。若需要精确匹配语义且无过度清除风险,请改用标签

清除全部

失效调用入口点存储的每个缓存响应:

src/index.jsjs
export default {
	async fetch(request, env, ctx) {
		await ctx.cache.purge({ purgeEverything: true });

		return new Response("Purged", { status: 200 });
	},
};
src/index.tsts
export default {
	async fetch(request, env, ctx): Promise<Response> {
		await ctx.cache.purge({ purgeEverything: true });

		return new Response("Purged", { status: 200 });
	},
} satisfies ExportedHandler;

请谨慎使用。清除全部会导致后续所有请求缓存未命中,直到重新填充,这会暂时增加 Worker 及其调用的上游服务的负载。

清除传播

ctx.cache.purge() 触发的清除使用 Cloudflare 的 Instant Purge 基础设施,并以与 zone 级别清除相同的保证在全球范围内传播。

返回值

purge() 解析为结果对象。检查 success 以确认清除已被接受;若未成功,检查 errors

src/index.jsjs
export default {
	async fetch(request, env, ctx) {
		const result = await ctx.cache.purge({ tags: ["blog-posts"] });

		if (!result.success) {
			console.error("Cache purge failed", result.errors);
			return new Response("Purge failed", { status: 500 });
		}

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

		if (!result.success) {
			console.error("Cache purge failed", result.errors);
			return new Response("Purge failed", { status: 500 });
		}

		return new Response("Purged", { status: 200 });
	},
} satisfies ExportedHandler;

失败时,errors 中的每个错误包含数字 code 和可读 message,你可记录或返回给调用方。

速率限制

purge() 使用与 Cloudflare zone 清除 API 相同的速率限制系统。有关适用于你账户套餐的速率限制,请参阅可用性与限制。当清除被限流时,successfalseerrors 包含描述拒绝原因的错误条目。

这篇文档对您有帮助吗?