Wrangler CLI 初始化
Wrangler 是 Cloudflare Workers 的官方 CLI 工具,负责开发、预览和发布:
# 安装 Wrangler
npm install -g wrangler
# 或
bun add -g wrangler
# 登录 Cloudflare 账户
wrangler login
# 使用 Hono 官方模板创建 Workers 项目
bun create hono my-worker
# 选择 cloudflare-workers 模板
cd my-worker
bun install
生成的项目结构:
my-worker/
├── src/
│ └── index.ts # Hono 应用入口
├── wrangler.toml # Workers 配置文件
├── package.json
└── tsconfig.json
wrangler.toml 配置
# wrangler.toml
name = "my-api"
main = "src/index.ts"
compatibility_date = "2024-09-23" # 必须设置,锁定 API 版本
compatibility_flags = ["nodejs_compat"] # 启用 Node.js 兼容层
# 自定义域名路由
[[routes]]
pattern = "api.myapp.com/*"
zone_name = "myapp.com"
# KV 命名空间绑定
[[kv_namespaces]]
binding = "SESSIONS" # 代码中通过 c.env.SESSIONS 访问
id = "xxxxxxxxxxxxxxxx" # KV 命名空间 ID
# R2 存储桶绑定
[[r2_buckets]]
binding = "UPLOADS"
bucket_name = "my-uploads"
# D1 数据库绑定
[[d1_databases]]
binding = "DB"
database_name = "my-database"
database_id = "xxxxxxxxxxxxxxxx"
# 环境变量(非敏感)
[vars]
APP_ENV = "production"
API_VERSION = "v1"
# Secret 通过 wrangler secret 命令设置,不写在这里
Cloudflare 特有 API 使用
类型定义
// src/index.ts — 定义环境变量类型
import { Hono } from 'hono'
// 声明 Workers 绑定类型
type Env = {
// KV 命名空间
SESSIONS: KVNamespace
// R2 存储桶
UPLOADS: R2Bucket
// D1 数据库
DB: D1Database
// 环境变量
APP_ENV: string
// Secret(通过 wrangler secret 设置)
JWT_SECRET: string
}
const app = new Hono<{ Bindings: Env }>()
export default app
KV 存储(键值对数据库)
// KV 适合存储:Session、用户配置、缓存、特性标志等
app.post('/session/create', async (c) => {
const sessionId = crypto.randomUUID()
const sessionData = {
userId: 'user-123',
createdAt: new Date().toISOString(),
}
// 写入 KV,设置 TTL(秒)
await c.env.SESSIONS.put(
sessionId,
JSON.stringify(sessionData),
{ expirationTtl: 60 * 60 * 24 } // 24小时后自动删除
)
return c.json({ sessionId })
})
app.get('/session/:id', async (c) => {
const id = c.req.param('id')
const raw = await c.env.SESSIONS.get(id) // 不存在返回 null
if (!raw) {
return c.json({ error: 'Session not found' }, 404)
}
return c.json(JSON.parse(raw))
})
R2 对象存储
// R2 适合存储:用户上传的文件、图片、视频、导出数据等
app.put('/upload/:filename', async (c) => {
const filename = c.req.param('filename')
const body = await c.req.arrayBuffer()
const contentType = c.req.header('Content-Type') ?? 'application/octet-stream'
await c.env.UPLOADS.put(filename, body, {
httpMetadata: { contentType },
customMetadata: {
uploadedAt: new Date().toISOString(),
uploadedBy: c.get('userId') ?? 'anonymous',
},
})
return c.json({ key: filename, url: `/files/${filename}` })
})
app.get('/files/:filename', async (c) => {
const object = await c.env.UPLOADS.get(c.req.param('filename'))
if (!object) {
return c.json({ error: 'File not found' }, 404)
}
return new Response(object.body, {
headers: {
'Content-Type': object.httpMetadata?.contentType ?? 'application/octet-stream',
'Cache-Control': 'public, max-age=31536000',
'ETag': object.etag,
},
})
})
D1 数据库(边缘 SQLite)
// D1 是 Cloudflare 的 SQLite 兼容边缘数据库
app.get('/users', async (c) => {
const page = Number(c.req.query('page') ?? 1)
const limit = 20
const offset = (page - 1) * limit
// D1 使用 prepare().bind().all() 模式
const { results } = await c.env.DB
.prepare('SELECT id, name, email FROM users ORDER BY created_at DESC LIMIT ? OFFSET ?')
.bind(limit, offset)
.all<{ id: string; name: string; email: string }>()
return c.json({ users: results, page })
})
// 批量操作(事务)
app.post('/batch', async (c) => {
const [result1, result2] = await c.env.DB.batch([
c.env.DB.prepare('UPDATE users SET active = 1 WHERE role = ?').bind('user'),
c.env.DB.prepare('DELETE FROM sessions WHERE expires_at < ?').bind(new Date().toISOString()),
])
return c.json({
activated: result1.meta.changes,
deleted: result2.meta.changes,
})
})
开发与部署
# 本地开发服务器(模拟 Workers 环境)
wrangler dev
# 本地开发(使用远程绑定)
wrangler dev --remote
# 设置 Secret(加密存储,不会出现在代码中)
wrangler secret put JWT_SECRET
# 输入:你的 JWT 密钥
# 创建 KV 命名空间
wrangler kv:namespace create SESSIONS
# 输出 ID,填入 wrangler.toml
# 创建 D1 数据库
wrangler d1 create my-database
# 执行 D1 数据库迁移
wrangler d1 execute my-database --file=./migrations/001_init.sql
# 发布到生产(全球部署)
wrangler deploy
# 查看实时日志
wrangler tail
性能优势:全球边缘延迟
| 架构 | 北美用户 | 欧洲用户 | 亚洲用户 | 冷启动 |
|---|---|---|---|---|
| 传统服务器(美国) | ~30ms | ~120ms | ~200ms | 无(常驻) |
| Cloudflare Workers | ~5ms | ~8ms | ~10ms | ~5ms |
限制与注意事项
- CPU 时间限制 免费计划每次请求最多 10ms CPU 时间(挂钟时间可更长,等待 I/O 不消耗 CPU);付费计划最多 30s CPU 时间。复杂的计算密集型任务不适合 Workers。
-
包大小限制
每个 Worker 脚本压缩后最大 3MB(付费计划可到 10MB)。Hono 本身 14KB 远不是问题,但大型第三方库可能超限。使用
wrangler build检查包大小。 - 无文件系统 Workers 没有持久化文件系统。需要文件存储时使用 R2,需要键值数据时使用 KV,需要关系数据时使用 D1。
-
无原生模块
不能使用 Node.js 的 native addon(.node 文件)。启用
nodejs_compat兼容标志后,大部分 Node.js 内置模块(crypto、path、buffer 等)可以使用,但实现基于 polyfill。
Workers 不适合的场景:长时间运行的任务(超过30秒)、需要持久化 WebSocket 连接(可用 Durable Objects 解决)、大文件流式处理(内存限制 128MB)、使用大量 native Node.js 模块的遗留代码。