Chapter 06

Cloudflare Workers 部署

全球 300+ 边缘节点,<50ms 覆盖全球——Hono 的主战场完整部署指南

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

限制与注意事项

Workers 不适合的场景:长时间运行的任务(超过30秒)、需要持久化 WebSocket 连接(可用 Durable Objects 解决)、大文件流式处理(内存限制 128MB)、使用大量 native Node.js 模块的遗留代码。