上手教程
这个教程带你写一个最小的待办清单 API,重点不在业务逻辑,而在三种存储绑定的接入方式差别。看完你应该能判断自己的场景该选哪个。
todo-worker/├── src/│ ├── index.ts # fetch 入口与路由│ └── db.ts # 数据访问├── wrangler.jsonc # Worker 名、兼容性日期、绑定声明├── .dev.vars # 本地密钥,不要提交├── package.json└── test/ └── index.spec.ts文件夹
todo-worker/— Worker 项目根目录- …
src/index.ts— 导出fetch处理器,路由都在这src/db.ts— 把绑定调用包一层,方便换存储wrangler.jsonc— 声明name、compatibility_date、绑定.dev.vars— 本地开发用的 secret,被 gitignore 掉test/index.spec.ts—vitest-pool-worker里跑单测
路由:一个 Worker 怎么分发请求
Section titled “路由:一个 Worker 怎么分发请求”export default { async fetch(request, env, ctx) { const url = new URL(request.url);
if (url.pathname === '/todos' && request.method === 'GET') { return Response.json(await listTodos(env)); }
if (url.pathname === '/todos' && request.method === 'POST') { const body = await request.json<{ text: string }>(); const todo = await createTodo(env, body.text); return Response.json(todo, { status: 201 }); }
return new Response('Not Found', { status: 404 }); },} satisfies ExportedHandler<Env>;三种都能实现这个待办清单,差别在一致性、延迟和查询能力。
适合读多写少、按已知 key 取的缓存类数据。最终一致性,写入后全球生效最多可能延迟 60 秒。
{ "kv_namespaces": [{ "binding": "STORE", "id": "..." }] }import { env } from 'cloudflare:workers';
export async function listTodos() { const raw = await env.STORE.get('todos', 'json'); return raw ?? [];}
export async function createTodo(text: string) { const todos = (await env.STORE.get<todo[]>('todos', 'json')) ?? []; const todo = { id: crypto.randomUUID(), text, done: false }; await env.STORE.put('todos', JSON.stringify([...todos, todo])); return todo;}整个清单塞在一个 value 里,只在你数据量小的时候成立——KV 单 value 上限 25 MB,且这是全量读全量写。
存文件、图片、上传内容,没有 egress 流量费。不适合当数据库用,这里只是为了对照 API 形状。
{ "r2_buckets": [{ "binding": "STORE", "bucket_name": "todos" }] }import { env } from 'cloudflare:workers';
export async function listTodos() { const obj = await env.STORE.get('todos.json'); return obj ? await obj.json() : [];}要按条件查、要事务、要局部更新,就用 D1。它是真正的 SQLite 实例,强一致。
{ "d1_databases": [{ "binding": "DB", "database_name": "todos", "database_id": "..." }] }CREATE TABLE todo ( id TEXT PRIMARY KEY, text TEXT NOT NULL, done INTEGER NOT NULL DEFAULT 0, created_at INTEGER NOT NULL);import { env } from 'cloudflare:workers';
export async function listTodos() { const { results } = await env.DB.prepare('SELECT * FROM todo ORDER BY created_at').all(); return results;}
export async function createTodo(text: string) { const todo = { id: crypto.randomUUID(), text, done: 0, created_at: Date.now() }; await env.DB.prepare('INSERT INTO todo (id, text, done, created_at) VALUES (?, ?, ?, ?)') .bind(todo.id, todo.text, todo.done, todo.created_at) .run(); return todo;}建库和应用迁移:
npx wrangler d1 create todosnpx wrangler d1 execute todos --local --file=./migrations/0001_init.sqlnpx wrangler dev默认行为。KV/R2/D1 的数据落在 .wrangler/state,绑定不需要真实 id 也能跑,适合纯逻辑开发。
npx wrangler dev加 --remote 后请求走远端绑定,读到的是账号里真实的数据。调试线上数据问题时用。
npx wrangler dev --remote试一下:
curl -s -X POST localhost:8787/todos -d '{"text":"写文档"}' -H 'content-type: application/json'curl -s localhost:8787/todos