说明:本文由 Codex 根据作者提供的主题、对话素材与 Cloudflare 官方文档辅助生成,属于 AI 生成/整理内容,非作者原创。请读者自行甄别并交叉验证。
值得单独写一篇。Workers 是 Cloudflare 开发平台的运行时底座;不先分清 handler、ctx、env binding 与运行时 API,后续接触 Queues、Durable Objects、Workflows、Dynamic Workers 时,很容易把“触发方式”“资源能力”和“部署管理 API”混在一起。
本文回答的是:代码运行在 Worker 内时,可以调用哪些 API、它们在什么边界内工作,以及资源如何通过 env 被授予给代码。它不展开各产品的全部方法表;Queues、Durable Objects、Workflows、Dynamic Workers 与 Sandbox 已各有专题,文末会给出对应入口。
先划清三层 API#
“Workers API”在讨论中常指三种不同的东西:
| 层次 | 代码从哪里拿到 | 解决什么问题 | 例子 |
|---|---|---|---|
| 运行时 API | 全局对象或模块导入 | 处理 HTTP、流、缓存、HTML、WebSocket、加密、出站 TCP 等 | fetch()、Response、caches.default、HTMLRewriter |
| Binding API | handler 的 env 参数 | 访问被显式授予的 Cloudflare 资源 | env.DB、env.QUEUE、env.ROOMS |
| 控制面 REST API | 带 API Token 的管理请求 | 部署 Worker、管理版本、路由、账号资源 | Workers API、Account API |
本文的重点是前两层。控制面 REST API 面向 CI、IaC、发布平台和运维后台;它不应被当成 Worker 请求路径中的常规数据访问方式。Worker 内需要访问 Cloudflare 平台资源时,优先使用 binding:它既是更直接的调用入口,也把可访问的能力限制在配置中。
flowchart LR T["HTTP / Cron / Queue / Email / Tail"] --> H["Module handlers"] H --> C["ctx:生命周期与异步任务"] H --> E["env:最小权限 Bindings"] H --> R["运行时 I/O:HTTP、流、缓存、HTML、WebSocket、TCP"] E --> P["KV · D1 · R2 · DO · Queues · Workflows · Services"] R --> O["Response / 事件确认 / 日志"]
Module Worker:最小执行模型#
新代码应使用 Module Worker:导出一个对象,按触发类型提供方法。旧式 addEventListener(…) Service Worker 写法仍可见于存量项目,但不适合作为新项目的默认选择。
// wrangler.jsonc
{
"name": "workers-runtime-basics",
"main": "src/index.ts",
"compatibility_date": "2026-08-07",
"vars": {
"APP_NAME": "workers-runtime-basics"
}
}interface Env {
APP_NAME: string;
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
if (url.pathname === "/health") {
return Response.json({
ok: true,
app: env.APP_NAME,
});
}
return new Response("Not Found", { status: 404 });
},
} satisfies ExportedHandler<Env>;这里有三个稳定的入口:
request:本次 HTTP 请求;它的 body 是流,读取后不能自动再读一次。env:配置、密钥与资源 binding 的容器。它不是任意全局环境变量。ctx:本次调用的生命周期能力,例如在响应之后继续做短暂的非关键工作。
配置或 binding 改动后,运行 npx wrangler types 生成类型,能让 env、RequestInit.cf 等接口跟随当前 Worker 配置校验。compatibility_date 也不是装饰字段:它决定 Worker 采用哪一组运行时行为;更新日期前应在测试环境验证。
Handler:什么事件会启动 Worker#
| Handler | 典型签名 | 触发源 | 本文的使用建议 |
|---|---|---|---|
fetch | fetch(request, env, ctx) | HTTP 请求、Service Binding 的 HTTP 调用 | 最常用入口;返回 Response。 |
scheduled | scheduled(controller, env, ctx) | Cron Trigger | 定期扫描、汇总、触发后续任务;不要把它当作精确计时器。 |
queue | queue(batch, env, ctx) | Queue consumer | 由批量消息驱动;确认、重试、DLQ 请见 /docs/Cloudflare/queues-api-and-practice/。 |
email | email(message, env, ctx) | Email Routing | 收件、校验、转发或入库;它需要邮件路由配置。 |
tail | tail(events, env, ctx) | Tail Worker 日志流 | 独立处理日志/异常事件,避免在主请求中同步写入外部观测系统。 |
alarm | Durable Object class 的 alarm() 方法 | 某个 DO 的 Alarm | 不是普通 Worker 的顶层 handler;请见 /docs/Cloudflare/durable-objects/。 |
一个 Worker 可按需组合多个 handler。HTTP 路由通常留在 fetch;可靠的异步消费由 queue 接手;同一业务键下需要顺序协调、计时和状态,则交给一个 Durable Object。
ctx:响应、短暂后台工作与可靠任务的边界#
最常被误用的是 ctx.waitUntil()。它可以让一个 Promise 在 HTTP 响应发出后继续执行,但不是可靠队列:HTTP Worker 在响应完成或客户端断开后,所有 waitUntil() 共享的延长窗口最多约 30 秒。窗口结束、运行时异常或部署切换都可能让工作不能完成。
flowchart TD A["这项工作会影响当前响应吗?"] -->|会| B["直接 await;失败则明确返回错误"] A -->|不会| C["需要可靠执行、重试或超过短暂窗口吗?"] C -->|不需要| D["ctx.waitUntil(promise)"] C -->|需要可靠处理| E["投递 Queues"] E --> F["多步骤、等待事件或补偿?"] F -->|是| G["使用 Workflows"] F -->|否| H["Queue consumer 处理"]
适合 ctx.waitUntil() 的例子是写一条非关键访问日志、异步刷新一个公开缓存。订单扣款、webhook 投递、邮件发送、必须完成的数据写入,应使用 Queues;需要跨步骤重试、暂停、等待外部事件或补偿时,使用 /docs/Cloudflare/workflows-api-and-recovery/。
另外两个常见能力:
ctx.passThroughOnException():只适合“Worker 位于 origin 前、出现未处理异常时让请求回源”的 fail-open 代理。若请求 body 已被读取,运行时不能把它重新播放给 origin;它也无法绕过 CPU 或内存超限。ctx.exports与ctx.props:用于在同一 Worker 内生成受约束的 loopback binding / RPC 调用。前者需要enable_ctx_exportscompatibility flag,适合高级封装,不是普通模块间函数调用的替代品。
运行时 API 地图#
Workers 尽量采用 Web 标准,因此熟悉浏览器或 Node 的 Web API 后,大部分 I/O 可以直接迁移;差异集中在“边缘请求生命周期”和 Cloudflare 特有扩展。
| 类别 | 常用 API | 适合做什么 | 重要边界 |
|---|---|---|---|
| HTTP 与 URL | fetch、Request、Response、Headers、URL、FormData | 代理、API、边缘鉴权、请求改写 | Request/Response body 是单次消费的流;需复用时先 clone() 或设计流式管线。 |
| 流与编码 | ReadableStream、WritableStream、TransformStream、TextEncoder / TextDecoder | 大响应转发、流式生成、避免整包缓冲 | 不要为了方便先把大 body 全部读进内存。 |
| 加密与标准能力 | crypto.subtle、AbortSignal、WebAssembly、计时 / Performance API | 签名校验、取消、Wasm 计算与测量 | Node 内建模块需要显式 Node.js compatibility 支持;优先先用 Web 标准接口。 |
| Worker 扩展 | caches.default、HTMLRewriter、scheduler.wait() | 程序化缓存、流式 HTML 改写、可中止的延时 | 都有 Workers 专属语义;不能照搬浏览器或 Node 的缓存/计时假设。 |
| 长连接 | WebSocketPair、WebSocket | 单连接实时通信、协议升级 | 需要多连接共享状态、协调或休眠恢复时,用 Durable Objects。 |
| 出站网络 | connect() from cloudflare:sockets | 用 stream 连接数据库代理、SMTP、专有 TCP 服务 | 这是出站 TCP,不是用 Worker 监听入站 TCP 端口;每次调用中创建和关闭 socket。 |
| Worker 间调用 | Service Binding、WorkerEntrypoint、RPC | 不经公网 URL 调用内部 Worker | HTTP 调用和 RPC 调用都要 await;否则被调 Worker 可能在完成前结束。 |
Cache API:程序化的、数据中心本地的缓存#
caches.default 提供 match()、put()、delete()。它与通过响应头驱动的 CDN 缓存不是同一个机制;写入的条目不会自动复制到所有数据中心。因此它适合热点公开对象的本地加速,不能被当作全局一致的数据层。
async function fetchPublicWithCache(
request: Request,
ctx: ExecutionContext,
): Promise<Response> {
if (request.method !== "GET") {
return fetch(request);
}
const cache = caches.default;
const cached = await cache.match(request);
if (cached) {
return cached;
}
const response = await fetch(request);
const canCache =
response.ok &&
!response.headers.has("Set-Cookie") &&
!response.headers.get("Cache-Control")?.toLowerCase().includes("private");
if (canCache) {
ctx.waitUntil(
cache.put(request, response.clone()).catch((error) => {
console.error("cache write failed", error);
}),
);
}
return response;
}上例只应服务于公开的 GET 响应。认证 header、用户 cookie、租户权限差异和私有数据都必须纳入 cache key 或直接绕开缓存;不要用这个模式缓存登录后的页面。
HTMLRewriter:边读边改 HTML#
HTMLRewriter 不需要把整个 HTML 读入内存。它以流式解析器的方式匹配选择器,在上游响应流经时改写标签或文档节点,适合注入安全属性、替换局部内容、边缘 A/B 标记等。
function addExternalLinkPolicy(response: Response): Response {
return new HTMLRewriter()
.on('a[target="_blank"]', {
element(element) {
element.setAttribute("rel", "noopener noreferrer");
},
})
.transform(response);
}处理文本时要注意回调可能多次收到同一个逻辑文本节点的 chunk;跨 chunk 的匹配需要自己维护状态。
WebSocket 与 TCP:两种不同的长连接#
WebSocket 是 HTTP 升级后的双向消息通道:
function acceptWebSocket(): Response {
const [client, server] = Object.values(new WebSocketPair());
server.accept();
server.send("connected");
return new Response(null, {
status: 101,
webSocket: client,
});
}这个模式适合单条连接的收发。聊天室、协同编辑、房间广播、限流桶等“多个连接必须由同一协调者管理”的场景,应将连接归属到 /docs/Cloudflare/durable-objects/。
TCP Socket 则用于 Worker 主动连出:
import { connect } from "cloudflare:sockets";
const socket = connect({ hostname: "db.example.internal", port: 5432 });
const writer = socket.writable.getWriter();
const reader = socket.readable.getReader();它以 Web Streams 读写,并提供 opened、closed、close() 与 startTls() 等接口。不要在 global scope 创建后跨请求复用 socket,也不要把它理解为“在 Worker 上开放一个入站 TCP 服务”。
env:Binding 是授予给代码的能力#
binding 可以理解为“配置注入的最小权限能力”:只有在 Wrangler 配置中声明并部署的资源,才会出现在 env。这种边界比在请求路径中携带管理 API Token 更清晰,也便于本地、预览和生产环境使用不同资源。
| 分类 | 常见 binding | 何时使用 |
|---|---|---|
| 配置与安全 | 环境变量、Secrets、Secrets Store、mTLS、Rate Limiting | 注入非敏感配置/密钥、管理凭据、服务间身份和边缘限流。 |
| 数据与状态 | KV、R2、D1、Durable Objects、Vectorize、Hyperdrive | 读取配置或对象、存储文件、关系数据、按业务键协调状态、向量检索、数据库连接优化。 |
| 异步与编排 | Queues、Workflows | 可靠消费与重试;跨步骤、可恢复的长流程。 |
| 服务组合与动态代码 | Service Bindings、Dynamic Worker Loaders、Dispatcher、Version Metadata | 内部微服务 RPC/HTTP、受控运行时加载、分发与版本识别。 |
| AI、媒体与观测 | AI、Analytics Engine、Assets、Browser Run、Images、Media Transformations、Stream | 模型调用、指标写入、静态资源、浏览器自动化与媒体处理。 |
几个容易混淆的选择:
- KV / R2 / D1 是数据服务;Durable Object 是带身份的状态协调者。需要针对单一业务键串行化时,优先考虑 DO。
- Queue 是可靠异步消息通道;Workflow 是持久化步骤编排。不要用
waitUntil冒充其中任何一个。 - Service Binding 用于 Worker 到 Worker 的内部调用;它支持
env.CATALOG.fetch(request),也支持由WorkerEntrypoint暴露的 RPC 方法。内部调用不需要给目标服务公开 URL。 - Dynamic Worker Loader 与 Sandbox 面向受控动态执行和隔离环境;它们不是普通
import()的替代品。详见 /docs/Cloudflare/dynamic-workers-api-and-security/ 与 /docs/Cloudflare/sandbox-sdk-api-and-practice/。
从需求反推 API#
| 需求 | 首选能力 | 不要误用成 |
|---|---|---|
| 路由、鉴权、改写请求、调用后端 | fetch + Request/Response | 在 Worker 中调用自己的公网 URL 形成无意义回环。 |
| 为公开内容做边缘局部缓存 | Cache API 或正确的 HTTP 缓存头 | 把 caches.default 当全局数据库。 |
| 改写 HTML,不想整页读入内存 | HTMLRewriter | await response.text() 后再处理大型页面。 |
| 连接浏览器客户端 | WebSocketPair | 用普通 HTTP 轮询模拟双向实时协作。 |
| 协调一组 WebSocket、房间或锁 | Durable Objects | 把可变全局变量当共享状态。 |
| 在响应后做可丢失的小任务 | ctx.waitUntil() | 把关键任务放进 waitUntil。 |
| 异步执行且需要重试、DLQ | Queues | 在 fetch 内无限重试。 |
| 跨天等待、事件恢复、补偿 | Workflows | 用 Cron + 自建状态机拼接可靠流程。 |
| Worker 内部调用 | Service Binding / RPC | 为内部服务暴露公网路由和长期 API Token。 |
实战检查清单#
- 使用 Module Worker,并为每个环境固定且测试过的
compatibility_date。 - 用
env取得 binding;普通变量放vars,密钥放 secret,不把 secret 写进仓库。 - 把影响当前结果的 I/O
await;只把可丢失、短暂的工作放入ctx.waitUntil()。 - 把大 body 当 stream 处理;明确何处消费、何处
clone()。 - 缓存前先判断公开性、身份差异和数据中心本地性。
- 多连接协调和按键串行化交给 Durable Objects;可靠异步交给 Queues;跨步骤恢复交给 Workflows。
- 每次新增或修改 binding 后运行
npx wrangler types与实际部署前的集成测试。
继续阅读#
- Workers Runtime APIs
- Handlers 与 ExecutionContext
- Bindings 与 Service Bindings
- Cache API、HTMLRewriter、WebSockets 与 TCP sockets
- /docs/Cloudflare/durable-objects/、/docs/Cloudflare/queues-api-and-practice/、/docs/Cloudflare/workflows-api-and-recovery/、/docs/Cloudflare/dynamic-workers-containers-sandbox/