KernelRanch
返回文章列表

Workers 代码编写教学:一个 fetch 函数能做什么

2026-11-10 #Cloudflare

Workers 的运行模型极简:每次请求调用一次 fetch(request),你返回一个 Response。没有路由框架、没有中间件栈,全部自己写——这也意味着行为完全可预期。

1. 函数的形状

export default {
  async fetch(request, env, ctx) {
    return new Response("hello");
  }
};
参数是什么
request标准 Request 对象:url、method、headers、body
env绑定的资源与变量(KV、环境变量、secrets)
ctx执行上下文:waitUntil()、passThroughOnException()

ctx.waitUntil() 用来把"响应之后的活"挂住,比如写日志,不阻塞返回。

2. 用 URL 做路由

const url = new URL(request.url);
switch (url.pathname) {
  case "/api/time":
    return Response.json({ now: Date.now() });
  case "/api/echo":
    return Response.json({ q: url.searchParams.get("q") });
  default:
    return new Response("Not Found", { status: 404 });
}

URL 是标准对象,pathname 和 searchParams 都能直接用。不需要自己解析字符串。

3. 返回 JSON 与自定义头

Response.json() 会自动设置 content-type: application/json。要加头就传第二个参数:

return Response.json(data, {
  status: 201,
  headers: { "cache-control": "no-store", "x-api-version": "1" }
});

想改请求头再转发给上游,需要构造新的 Request:

const upstream = await fetch("https://api.example.com/data", {
  headers: { "authorization": `Bearer ${env.TOKEN}` }
});
return new Response(upstream.body, upstream);

new Response(upstream.body, upstream) 是流式转发的写法,不会把整个响应读进内存。

4. cf 对象:不用查 IP 库

const cf = request.cf;
// cf.country / cf.city / cf.colo / cf.asn / cf.tlsVersion

实测返回值(我的示例站点 /api/ip):

{"ip":"218.188.154.160","country":"HK","colo":"HKG"}

cf-connecting-ip 是 Cloudflare 写入的真实客户端 IP;cf 对象是边缘附带的元数据。两者都不需要额外接口。

5. 三个真实会踩的错

body 只能读一次。先 await request.text() 再 await request.json() 会抛 TypeError: Body has already been consumed。要么克隆一份 request.clone(),要么只读一次并把结果传下去。

忘记 404。默认不写 default 分支就返回首页,实测访问 /nope 得到 200。语义上应该是 404,监控里也才会区分。

异步没 await。fetch(...) 忘了 await,返回的是 Promise,序列化成 {},页面看起来"没数据"但不报错。这是最常见的静默失败。

6. 本地调试

wrangler dev          # 本地起服务,默认 http://localhost:8787
wrangler tail         # 看线上 Worker 的实时日志

wrangler dev 支持热重载;线上排错用 wrangler tail,比在代码里 console.log 再重新部署快得多。细节见 65-wrangler-dev-debug.md。

小结

Workers 的编程模型只有一句:收一个 Request,还一个 Response。路由、鉴权、缓存、转发都是这句话的组合。

写的时候守住三条:body 只读一次、每个分支都要有默认返回、每个 await 都不要漏。这三点覆盖了我实际踩过的大部分问题,而且都不会在部署时报错,只在运行时表现为"行为不对"。

数据来源与检索时间

检索时间 2026-11-10。cf 对象的实际返回值为本机部署验证。

来源URL对应数据
Workers 入门指南https://developers.cloudflare.com/workers/get-started/guide/fetch 处理函数的基本结构与项目组织
Workers 路由https://developers.cloudflare.com/workers/configuration/routing/routes/路径匹配与路由配置方式
Workers 限额https://developers.cloudflare.com/workers/platform/limits/单次请求 50 个子请求、128MB 内存等运行时约束

核验说明

  • cf.country / cf.colo / cf-connecting-ip 的返回值来自本机对已部署 Worker 的真实请求(country=HK、colo=HKG)。
  • body 重复读取的报错为常见行为,本条依据运行时语义描述,未单独构造复现。
  • 未做:没有测 ctx.waitUntil() 在请求结束后继续执行的时序,也没有测流式转发的内存占用。