DevToolBox免费
博客

Cloudflare Workers 完全指南:KV、D1、R2、Durable Objects 与 Hono

15 分钟作者 DevToolBox

Cloudflare Workers 是一个无服务器边缘计算平台,在全球 300+ 数据中心运行你的代码。与在特定区域运行的传统无服务器平台不同,Workers 在最靠近用户的边缘执行,提供亚毫秒级冷启动和超低延迟。

什么是 Cloudflare Workers?

Workers 是在 Cloudflare 边缘网络上运行的 JavaScript/TypeScript 函数。它们使用 V8 引擎在轻量级隔离环境中运行。

主要特性

  • 亚毫秒级冷启动(V8 隔离,无容器启动)
  • 0ms 调度:代码立即运行
  • 全球部署:300+ 数据中心
  • Web 标准 API:fetch、Request、Response、crypto
  • 免费层:每天 100,000 请求
  • 自动扩展:无需配置即可处理流量峰值

入门

使用 Wrangler CLI 在几分钟内创建和部署 Worker。

# Install Wrangler CLI
npm install -g wrangler

# Authenticate
wrangler login

# Create a new Worker project
npm create cloudflare@latest my-worker
cd my-worker

# Project structure
# my-worker/
# ├── src/
# │   └── index.ts       # Worker entry point
# ├── wrangler.toml       # Configuration
# ├── package.json
# └── tsconfig.json

# Local development
wrangler dev

# Deploy to production
wrangler deploy

请求处理模式

Workers 使用 Web 标准 fetch 事件模型。

// src/index.ts - Basic Worker
export interface Env {
  MY_KV: KVNamespace;
  MY_DB: D1Database;
  MY_BUCKET: R2Bucket;
}

export default {
  async fetch(
    request: Request,
    env: Env,
    ctx: ExecutionContext
  ): Promise<Response> {
    const url = new URL(request.url);

    // Simple routing
    switch (url.pathname) {
      case "/":
        return new Response("Hello from the Edge!", {
          headers: { "content-type": "text/plain" },
        });

      case "/api/data":
        return Response.json({ time: Date.now(), edge: true });

      case "/api/headers":
        const headers: Record<string, string> = {};
        request.headers.forEach((v, k) => (headers[k] = v));
        return Response.json(headers);

      default:
        return new Response("Not Found", { status: 404 });
    }
  },
};

URL 路由

Workers 没有内置路由器,但可以使用 URL 模式匹配或 Hono 框架实现路由。

// URL Pattern-based routing (built-in Web API)
const routes = [
  { pattern: new URLPattern({ pathname: "/api/users/:id" }), handler: getUser },
  { pattern: new URLPattern({ pathname: "/api/users" }), handler: listUsers },
  { pattern: new URLPattern({ pathname: "/api/posts/:slug" }), handler: getPost },
];

async function getUser(request: Request, params: Record<string, string>) {
  return Response.json({ id: params.id, name: "Alice" });
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const url = request.url;

    for (const route of routes) {
      const match = route.pattern.exec(url);
      if (match) {
        return route.handler(request, match.pathname.groups);
      }
    }
    return new Response("Not Found", { status: 404 });
  },
};

KV:键值存储

Workers KV 是全球分布的最终一致性键值存储,优化用于高读低写工作负载。

// wrangler.toml
// [[kv_namespaces]]
// binding = "CACHE"
// id = "abc123"

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const url = new URL(request.url);
    const cacheKey = `page:${url.pathname}`;

    // Read from KV (returns null if not found)
    const cached = await env.CACHE.get(cacheKey);
    if (cached) {
      return new Response(cached, {
        headers: { "x-cache": "hit", "content-type": "text/html" },
      });
    }

    // Generate and cache the response
    const html = `<html><body><h1>Page: ${url.pathname}</h1></body></html>`;

    // Store in KV with 1 hour TTL
    await env.CACHE.put(cacheKey, html, { expirationTtl: 3600 });

    return new Response(html, {
      headers: { "x-cache": "miss", "content-type": "text/html" },
    });
  },
};

// KV supports JSON, text, streams, and ArrayBuffer
// await env.CACHE.put("config", JSON.stringify(config));
// const config = await env.CACHE.get("config", "json");

D1:边缘 SQLite

D1 是基于 SQLite 构建的无服务器 SQL 数据库,在边缘运行,提供低延迟数据库访问。

// Create D1 database
// wrangler d1 create my-database

// wrangler.toml
// [[d1_databases]]
// binding = "DB"
// database_name = "my-database"
// database_id = "xxx-xxx"

// schema.sql
// CREATE TABLE users (
//   id INTEGER PRIMARY KEY AUTOINCREMENT,
//   name TEXT NOT NULL,
//   email TEXT UNIQUE NOT NULL,
//   created_at TEXT DEFAULT (datetime('now'))
// );

// Apply schema: wrangler d1 execute my-database --file=schema.sql

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const url = new URL(request.url);

    if (url.pathname === "/api/users" && request.method === "GET") {
      const { results } = await env.DB.prepare(
        "SELECT * FROM users ORDER BY created_at DESC LIMIT 50"
      ).all();
      return Response.json(results);
    }

    if (url.pathname === "/api/users" && request.method === "POST") {
      const { name, email } = await request.json<{ name: string; email: string }>();
      const result = await env.DB.prepare(
        "INSERT INTO users (name, email) VALUES (?, ?)"
      ).bind(name, email).run();
      return Response.json({ id: result.meta.last_row_id }, { status: 201 });
    }

    // Batch queries (single round trip)
    if (url.pathname === "/api/stats") {
      const [users, posts] = await env.DB.batch([
        env.DB.prepare("SELECT COUNT(*) as count FROM users"),
        env.DB.prepare("SELECT COUNT(*) as count FROM posts"),
      ]);
      return Response.json({
        users: users.results[0],
        posts: posts.results[0],
      });
    }

    return new Response("Not Found", { status: 404 });
  },
};

R2:对象存储

R2 是兼容 S3 的对象存储,零出口费用。适合存储图片、文件和静态资源。

// wrangler.toml
// [[r2_buckets]]
// binding = "STORAGE"
// bucket_name = "my-files"

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const url = new URL(request.url);
    const key = url.pathname.slice(1); // remove leading /

    // Upload file
    if (request.method === "PUT") {
      await env.STORAGE.put(key, request.body, {
        httpMetadata: {
          contentType: request.headers.get("content-type") || "application/octet-stream",
        },
      });
      return Response.json({ key, uploaded: true });
    }

    // Download file
    if (request.method === "GET") {
      const object = await env.STORAGE.get(key);
      if (!object) return new Response("Not Found", { status: 404 });

      return new Response(object.body, {
        headers: {
          "content-type": object.httpMetadata?.contentType || "application/octet-stream",
          "etag": object.httpEtag,
        },
      });
    }

    // Delete file
    if (request.method === "DELETE") {
      await env.STORAGE.delete(key);
      return Response.json({ key, deleted: true });
    }

    return new Response("Method not allowed", { status: 405 });
  },
};

使用 Hono 框架构建

Hono 是为边缘运行时设计的轻量级 Web 框架,提供路由、中间件和类型安全。

// Using Hono framework with Workers
import { Hono } from "hono";
import { cors } from "hono/cors";
import { jwt } from "hono/jwt";

type Bindings = { DB: D1Database; STORAGE: R2Bucket; JWT_SECRET: string };
const app = new Hono<{ Bindings: Bindings }>();

// Middleware
app.use("/api/*", cors());
app.use("/api/protected/*", async (c, next) => {
  const jwtMiddleware = jwt({ secret: c.env.JWT_SECRET });
  return jwtMiddleware(c, next);
});

// Routes
app.get("/", (c) => c.text("Hello Hono on Workers!"));

app.get("/api/users", async (c) => {
  const { results } = await c.env.DB.prepare("SELECT * FROM users").all();
  return c.json(results);
});

app.post("/api/users", async (c) => {
  const { name, email } = await c.req.json();
  const result = await c.env.DB.prepare(
    "INSERT INTO users (name, email) VALUES (?, ?)"
  ).bind(name, email).run();
  return c.json({ id: result.meta.last_row_id }, 201);
});

app.get("/api/protected/me", (c) => {
  const payload = c.get("jwtPayload");
  return c.json({ user: payload });
});

export default app;

性能最佳实践

  • 使用 Cache API 在边缘缓存响应
  • 在请求内缓存 KV 值以减少读取
  • 对大型负载使用流式响应
  • 保持 Worker 脚本小巧以减少冷启动时间
  • 使用 D1 批量查询减少往返
  • 使用 R2 存储静态资源
  • 使用 Durable Objects 进行协调
  • 为频繁调用源服务器的 Workers 启用智能放置

常见问题

Cloudflare Workers 费用多少?

免费层包括每天 100,000 请求。付费计划每月 5 美元,包括 1000 万请求、D1、KV 和 R2。

Workers 能取代传统后端吗?

对于许多应用可以。D1 用于数据库、R2 用于文件存储、KV 用于缓存、Durable Objects 用于有状态逻辑。

D1 已经准备好用于生产了吗?

D1 已正式可用且适合生产使用。支持完整 SQL、事务和自动读复制。

Workers 与 AWS Lambda 相比如何?

Workers 冷启动更快、距离用户更近、部署更简单。Lambda 支持更多语言和更长执行时间。

可以在 Workers 中使用 npm 包吗?

可以,使用 node_compat 标志。依赖 Node.js 特定 API 的包不工作,但 zod、hono 等流行包可以正常使用。

𝕏 Twitterin LinkedIn
这篇文章有帮助吗?

保持更新

获取每周开发技巧和新工具通知。

无垃圾邮件,随时退订。

试试这些相关工具

{ }JSON Formatter#Hash GeneratorSQLSQL Formatter

相关文章

SQLite 生产环境指南:WAL 模式、Litestream、Turso 和 D1

SQLite 生产环境完全指南,涵盖 WAL 模式、Litestream 复制、Turso 和 Cloudflare D1。

API 限流指南:策略、算法与实现

API 限流完整指南。学习令牌桶、滑动窗口、漏桶算法及代码示例。包含 Express.js 中间件、Redis 分布式限流和最佳实践。

Zod 验证指南:Schema、转换、精细化与 tRPC 集成

TypeScript 中 Zod 模式验证完全指南:定义 schema、数据转换、自定义精细化与 tRPC 集成。