跳到主要内容

《林一的 Cloudflare 通关记》第 5 篇-网站要有个"厨房"——Cloudflare Workers搭建后端API

· 阅读需 16 分钟

《林一的 Cloudflare 通关记》第 5 篇

周一早上,林一兴冲冲地打开电脑,准备给"星火AI"的前端页面加上后端接口。

上周他用 Cloudflare Pages 把前端部署上线了,页面看着挺漂亮,但点来点去只有一个静态展示页。产品经理小王周五下班前甩来一句话:"这个网站不能交互,跟PPT有什么区别?用户连个注册登录都做不了。"

故事引入

林一心想,确实该搭后端了。他熟练地打开某云服务器购买页面,2核4G的机器一年也要好几百块,正准备点击"立即购买"——

"又花钱?"一只手从背后伸过来,按住了他的鼠标。

老张端着保温杯,一脸"我就知道你会这样"的表情。

"林一啊,上周 DNS、SSL、CDN、Pages,一分钱没花对吧?怎么到了后端这儿,就想不起来了?"

"后端不一样啊张哥,前端是静态文件,放 CDN 上就行。后端要跑代码,总得有台服务器吧?"林一指了指屏幕上的云服务器配置。

"谁告诉你跑代码就得买服务器?"老张拉过一把椅子坐下,"听说过 Serverless 没有?"

"无服务器?"林一挠挠头,"没有服务器,代码跑在哪儿?"

"跑在 Cloudflare 的边缘节点上。"老张打开 Cloudflare 的控制台,"用 Cloudflare Workers,你写一个函数,部署上去,它就在全球几百个节点上跑。免费额度每天十万次请求,对你这个实习项目来说,绰绰有余。"

"十万次?免费?"林一关掉了云服务器购买页面。


技术讲解

Serverless:不是没有服务器,是你不用管服务器

老张在白板上写了两个词:ServerlessFaaS

"Serverless 这个名字起得有点误导人,"老张说,"服务器当然存在,只是你不需要管了。你不用操心服务器的采购、配置、操作系统安装、安全补丁、扩容缩容——这些全由平台帮你搞定。你只管写代码,部署上去就能跑。"

"那 FaaS 又是什么?"

"FaaS,全称 Function as a Service,函数即服务。这是 Serverless 的一种实现模式。"老张画了一张对比图:

传统方式:买服务器 → 装系统 → 装运行环境 → 部署应用 → 24小时运行 → 流量来了扩容 → 流量走了缩容
FaaS方式:写函数 → 部署 → 完了(流量来了自动跑,流量走了自动歇)

Serverless vs FaaS 对比

"传统方式就像你自己开一家餐厅——租店面、买厨具、雇厨师、交水电费,不管有没有客人来,成本都在烧。FaaS 就像一个共享厨房——你带上菜谱,有订单来了就做,做完了走人,厨房的维护跟你没关系。"

林一若有所思:"那这个共享厨房……是谁在维护?"

"在 Cloudflare 的场景里,就是 Cloudflare 的全球网络。你把函数丢上去,Cloudflare 负责把它分发到全球各地的服务器上,用户访问的时候,离用户最近的那个节点来执行你的代码。"

"这跟国内那些 Serverless 服务,比如阿里云函数计算、腾讯云 SCF 有什么区别?"

"好问题。最大的区别在于部署位置。传统云厂商的 Serverless,函数跑在几个集中的区域机房里,比如北京、上海、深圳。用户在广州访问,请求要跑到上海去执行,再跑回来,光网络延迟就几十毫秒。而 Cloudflare Workers 跑在边缘节点上——"

边缘计算 vs 传统云计算:代码出发找用户

老张又在白板上画了两个图:

传统云计算:
用户(广州) → 请求 → [上海机房] → 处理 → 响应 → 用户(广州)
延迟:30-80ms

边缘计算:
用户(广州) → 请求 → [广州边缘节点] → 处理 → 响应 → 用户(广州)
延迟:1-5ms

边缘计算 vs 传统云计算

"看到区别了吗?传统云计算是用户去找机房,边缘计算是代码去找用户。"

"Cloudflare 在全球一百多个国家、三百多个城市部署了节点。你部署一个 Worker,它不是部署在某一台机器上,而是分发到所有这些节点上。广州用户访问,广州节点处理;东京用户访问,东京节点处理;纽约用户访问,纽约节点处理。每个用户都享受最低延迟。"

"这也太爽了吧?"林一眼睛放光。

"而且不只是延迟低。"老张补充道,"传统服务器你还得担心高并发扛不扛得住。Workers 的边缘架构天然就是分布式的,流量被分散到全球几百个节点上,不存在单点压力。"

Workers 运行原理:为什么不用 Docker?

"好了,接下来是重点。"老张喝了口茶,"Cloudflare Workers 跑代码的方式,跟绝大多数 Serverless 平台都不一样。"

"有什么特别的?"

"大多数 Serverless 平台——AWS Lambda、阿里云函数计算、腾讯云 SCF——都用的容器模型。每个函数被打包成一个 Docker 容器镜像,部署到服务器上。请求来了,启动容器、加载运行环境、执行代码。"

"这有什么问题吗?"

"问题在于冷启动。"老张在白板上写下一串数字:

容器冷启动流程:
拉取镜像 → 创建容器 → 启动容器 → 加载语言运行时 → 加载代码 → 执行
5-10秒 1-2秒 1-3秒 500ms-2s 100ms → 总计:8-17秒

"这么久?!"林一吓了一跳。

"当然,这是最坏情况。大多数平台做了优化,冷启动通常在 1-3 秒。但对于实时 API 来说,1 秒的延迟已经很致命了。"

"那 Cloudflare Workers 呢?"

"Workers 不用容器,也不用虚拟机。它用的是 V8 Isolate。"

老张在白板上重重地写下这个词。

V8 Isolate:Cloudflare 的秘密武器

"你知道 Chrome 浏览器用什么引擎跑 JavaScript 吗?"

"V8 引擎。"林一脱口而出。

"对。Node.js 也是用 V8。Cloudflare Workers 同样用 V8。但关键在于,Workers 不是给每个函数启动一个独立的 Node.js 进程或容器,而是在一个已经运行的 V8 实例中,创建一个 Isolate(隔离体)。"

"Isolate 是什么?"

"你可以把 V8 引擎想象成一座大厦,Isolate 就是大厦里的一间办公室。每间办公室有自己的门锁、自己的资源、自己的代码,互相完全隔离。但它们共享大厦的基础设施——电梯、水电、消防系统。"

传统容器模型:               V8 Isolate 模型:
┌─────────┐ ┌─────────┐ ┌──────────────────────┐
│ 容器1 │ │ 容器2 │ │ V8 引擎实例 │
│ Node.js │ │ Node.js │ │ ┌──────┐ ┌──────┐ │
│ 代码A │ │ 代码B │ │ │Isolate│ │Isolate│ │
│ ~50MB │ │ ~50MB │ │ │ 代码A │ │ 代码B │ │
└─────────┘ └─────────┘ │ │~2-3MB │ │~2-3MB │ │
│ └──────┘ └──────┘ │
启动:1-3秒 │ ...成千上万个... │
└──────────────────────┘
启动:~5毫秒

V8 Isolate vs 容器模型

"看到区别了吗?容器模型里,每个函数要带一个完整的 Node.js 运行时,内存占用 50MB 起步。而 V8 Isolate 复用同一个 V8 引擎,每个 Isolate 只占 2-3MB 内存,而且创建速度极快——大约 5 毫秒。"

"5 毫秒?!比容器快了几百倍?"

"差不多。官方说法是,一个 Isolate 的启动速度大约是传统容器或虚拟机上 Node 进程的一百倍,内存消耗低一个数量级。"

"所以 Workers 没有冷启动问题?"

"几乎可以忽略不计。5 毫秒的启动时间,用户完全感知不到。这也是为什么 Workers 适合做 API 的原因——每个请求都是即时响应。"

老张继续解释:"而且因为 Isolate 之间内存完全隔离,一个 Worker 的代码不可能访问到另一个 Worker 的内存,安全性有保障。Cloudflare 在一台物理机上可以跑成千上万个 Isolate,资源利用率极高,这就是它能把免费额度给到十万次请求/天的底气。"

林一忍不住算了一下:"十万次请求,如果每次算 5 毫秒启动加执行,一台机器一天能跑……"

"别算了,"老张笑,"反正比你那台 2 核 4G 的云服务器强得多。"

wrangler CLI:Workers 的"遥控器"

"理论讲完了,开始实操。"老张打开终端,"Workers 的开发工具叫 wrangler,是 Cloudflare 官方的命令行工具。项目创建、本地开发、部署上线,全都靠它。"

"就像 Git 之于代码管理?"

"对,差不多。wrangler 就是 Workers 的遥控器。"

安装与初始化

# 创建新项目(推荐方式,使用 C3 脚手架)
npm create cloudflare@latest -- spark-api

# 按提示选择:
# - What would you like to start with? → Hello World example
# - Which template would you like to use? → Worker only
# - Which language do you want to use? → JavaScript
# - Do you want to use git for version control? → Yes
# - Do you want to deploy your application? → No

"这个命令会自动创建项目结构,并且把 wrangler 作为开发依赖装好。"

老张指着生成的文件列表:

spark-api/
├── src/
│ └── index.js # Worker 入口文件
├── wrangler.jsonc # Wrangler 配置文件
├── package.json
├── package-lock.json
└── node_modules/

"注意,以前 Workers 的配置文件叫 wrangler.toml,新版本改成了 wrangler.jsonc(JSON with Comments)。两者的配置内容一样,只是格式变了。"

wrangler.jsonc 配置文件

{
"name": "spark-api",
"main": "src/index.js",
"compatibility_date": "2025-01-01"
}

"三个关键字段:name 是 Worker 的名称,也是访问 URL 的一部分;main 指定入口文件;compatibility_date 控制运行时的兼容性特性版本,建议设为较新的日期以启用最新功能。"

本地开发

# 进入项目目录
cd spark-api

# 启动本地开发服务器
npx wrangler dev

"第一次运行 wrangler dev 会弹出一个浏览器窗口让你登录 Cloudflare 账号。登录之后,本地开发服务器就跑起来了,默认地址是 http://localhost:8787。你改了代码保存,自动热重载,所见即所得。"

部署上线

# 部署到 Cloudflare 全球网络
npx wrangler deploy

"一行命令,代码就被分发到全球三百多个城市的节点上。部署完成后,你会得到一个 https://spark-api.<你的子域>.workers.dev 的地址,全世界都能访问。"

"这也太简单了吧?"林一有点不敢相信,"不用配 Nginx?不用配 SSL 证书?不用配防火墙?"

"都不用。SSL 自带的,CDN 自带的,DDoS 防护也自带的。你只管写代码。"


实操指导

编写第一个 Worker:API 路由处理

"好了,"老张拍拍手,"现在来写真正的后端 API。"

他打开 src/index.js,默认代码是这样的:

export default {
async fetch(request, env, ctx) {
return new Response("Hello World!");
},
};

"这个 fetch 函数就是入口。每次有 HTTP 请求到达,Cloudflare 就调用这个函数,传入三个参数:"

参数说明
requestHTTP 请求对象,包含 URL、方法、请求头、请求体等
env环境变量和 Bindings(绑定资源,如数据库、KV 等)
ctx执行上下文,用于管理异步任务的生命周期

Worker fetch 函数三参数

"现在我们来写一个真正的 API 路由系统。星火AI 需要几个基础接口:"

export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
const path = url.pathname;
const method = request.method;

// 设置 CORS 响应头(前端跨域调用必需)
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
};

// 处理 CORS 预检请求
if (method === "OPTIONS") {
return new Response(null, { headers: corsHeaders });
}

// 路由匹配
try {
let response;

if (path === "/api/health" && method === "GET") {
// 健康检查接口
response = new Response(
JSON.stringify({
status: "ok",
service: "spark-api",
timestamp: Date.now(),
}),
{ headers: { "Content-Type": "application/json", ...corsHeaders } }
);
} else if (path === "/api/user/info" && method === "GET") {
// 获取用户信息(示例:从查询参数读取用户ID)
const userId = url.searchParams.get("id");
if (!userId) {
response = new Response(
JSON.stringify({ error: "缺少参数: id" }),
{
status: 400,
headers: { "Content-Type": "application/json", ...corsHeaders },
}
);
} else {
response = new Response(
JSON.stringify({
id: userId,
name: "林一",
role: "intern",
createdAt: "2025-07-01",
}),
{ headers: { "Content-Type": "application/json", ...corsHeaders } }
);
}
} else if (path === "/api/user/register" && method === "POST") {
// 用户注册接口
const body = await request.json();
const { username, email } = body;

if (!username || !email) {
response = new Response(
JSON.stringify({ error: "用户名和邮箱不能为空" }),
{
status: 400,
headers: { "Content-Type": "application/json", ...corsHeaders },
}
);
} else {
response = new Response(
JSON.stringify({
message: "注册成功",
user: { id: Date.now(), username, email },
}),
{
status: 201,
headers: { "Content-Type": "application/json", ...corsHeaders },
}
);
}
} else {
// 404 路由不存在
response = new Response(
JSON.stringify({ error: `路由不存在: ${method} ${path}` }),
{
status: 404,
headers: { "Content-Type": "application/json", ...corsHeaders },
}
);
}

return response;
} catch (error) {
// 统一错误处理
return new Response(
JSON.stringify({ error: "服务器内部错误", detail: error.message }),
{
status: 500,
headers: { "Content-Type": "application/json", ...corsHeaders },
}
);
}
},
};

"这段代码虽然长了点,但逻辑很清晰。"老张逐段讲解:

1. 路由解析:用 new URL(request.url) 解析请求 URL,拿到 pathname(路径)和 method(HTTP 方法),然后通过 if/else 匹配不同的路由。这就是最基础的路由实现方式。

2. 路径参数 vs 查询参数

  • 查询参数/api/user/info?id=123,用 url.searchParams.get("id") 获取
  • 路径参数:如果设计成 /api/user/123,则需要用正则或字符串分割来提取

"如果要处理路径参数,可以这样做:"老张补充了一个示例:

// 匹配 /api/user/123 格式的路径
const userMatch = path.match(/^\/api\/user\/(\d+)$/);
if (userMatch && method === "GET") {
const userId = userMatch[1]; // "123"
// ... 返回用户信息
}

3. 请求体解析:POST/PUT 请求带 JSON body 时,用 await request.json() 解析。这是 Workers 运行时提供的标准 Web API,跟浏览器里的 fetch 用法一致。

4. 响应构建new Response(body, { status, headers }) 构建响应。Content-Type 设为 application/json,并附加 CORS 头。

5. CORS 处理:前端和后端不在同一个域名下时,浏览器会发跨域预检请求(OPTIONS)。这里统一处理了 CORS,前端就能无障碍调用。

RESTful API 设计要点

老张在白板上列出了星火AI 的 API 设计:

GET    /api/health          → 健康检查
GET /api/user/info → 获取用户信息(查询参数: id)
POST /api/user/register → 用户注册
PUT /api/user/profile → 更新用户资料
DELETE /api/user/account → 注销账号

"RESTful 的核心原则就是:用 HTTP 方法表示操作,用 URL 路径表示资源。GET 查询、POST 创建、PUT 更新、DELETE 删除。URL 用名词不用动词,接口语义一目了然。"

"跟国内那些 RPC 风格的 API 比呢?比如 /api/getUserInfo/api/createOrder 这种?"

"RESTful 更标准化、更符合 HTTP 语义,适合对外开放的 API。RPC 风格更直观,适合内部微服务。两种风格没有绝对优劣,但既然我们在学 Cloudflare,就按 RESTful 来。"

免费额度:够不够用?

"最后说说你最关心的问题——免费额度。"老张调出了 Cloudflare 官方的限制说明:

限制项免费计划
每日请求数100,000 次/天
CPU 时间10 毫秒/请求
内存128 MB
子请求数50 次/请求
Worker 大小(压缩后)3 MB
Worker 数量100 个/账户
环境变量64 个/Worker
启动时间≤ 1 秒

Workers 免费额度

"重点解释几个容易误解的:"

每日请求数 10 万次:这是绝对数量,不是并发数。一天 86400 秒,平均每秒约 1.16 次请求。对于个人项目和早期产品来说完全够用。超了会返回 Error 1027。

CPU 时间 10 毫秒:注意这是 CPU 时间,不是墙钟时间(wall time)。CPU 时间是指你的代码实际占用 CPU 执行的时间,不包括等待网络 I/O 的时间。比如你 fetch 一个外部 API 等了 200 毫秒返回,这 200 毫秒不算 CPU 时间。官方统计显示,大多数 Worker 平均每次请求仅消耗约 2.2 毫秒 CPU 时间。简单的 JSON API 远不会触及 10 毫秒的上限。

内存 128 MB:对于 JSON API 来说绰绰有余。但如果你要处理大文件、做图片处理,就要注意了。

子请求 50 次:一个 Worker 请求中可以发起的 fetch 调用次数上限。对于调用外部 API、查数据库等场景,50 次通常足够。

"那如果超了怎么办?"

"超了就升级到 Workers Paid 计划,每月 5 美元,请求额度变成 1000 万次/月,CPU 时间提升到 30 毫秒/请求。但对现在的你来说,免费计划完全够用。"


小结预告

本篇知识点回顾

知识点核心内容
Serverless / FaaS无需管理服务器,写函数即可运行,按请求计费
边缘计算 vs 传统云计算代码跑在离用户最近的边缘节点 vs 集中式机房,延迟从几十毫秒降到几毫秒
V8 IsolateWorkers 的核心隔离技术,复用 V8 引擎,启动 ~5ms,内存 ~2-3MB,比容器快约 100 倍
wrangler CLInpm create cloudflare@latest 创建项目,wrangler dev 本地开发,wrangler deploy 部署
Worker 代码结构export default { async fetch(request, env, ctx) {...} },处理 HTTP 请求并返回 Response
RESTful 路由设计用 HTTP 方法表示操作,URL 表示资源;路径参数用正则匹配,查询参数用 searchParams
免费额度10 万次请求/天,10ms CPU/请求,128MB 内存,50 次子请求/请求

动手挑战

  1. 基础挑战:按照文中步骤创建一个 Worker 项目,实现 /api/health 健康检查接口,部署到 workers.dev 域名
  2. 进阶挑战:给星火AI 添加一个 /api/chat 接口,接收 POST 请求中的 message 字段,暂时返回固定回复(比如 "收到消息:${message}"),为下一篇接入 AI 做准备
  3. 折腾挑战:尝试实现路径参数路由 /api/user/:id,支持 GET 请求返回对应用户的模拟数据

提示:本地开发用 npx wrangler dev,测试 API 推荐用 curl 或 Postman。部署后可以在 Cloudflare Dashboard 的 Workers 页面查看实时请求日志。

下回预告

林一把 API 部署上线,前端也能正常调用了。小王点开 /api/chat 接口试了一下,收到一句冷冰冰的 "收到消息:你好"

"这就是你说的 AI 平台?"小王皱眉,"这个网站连个 AI 功能都没有,叫什么星火AI?"

"呃……"林一看向老张。

老张不慌不忙地放下茶杯:"别急,下一篇,给你接入真正的大模型。Cloudflare Workers AI,免费跑 LLM,不用 API Key,不用调第三方,就在你的 Worker 里直接调用。"

林一的眼睛又亮了。

下篇预告:《AI 能力加持——Cloudflare Workers AI 接入大模型》


本文基于 Cloudflare 官方文档撰写,参考文档最后更新于 2026 年 7 月。技术内容以官方文档为准:https://developers.cloudflare.com/workers/

wp