六维教程

Cloudflare Workers KV 存储

上一篇的 CRUD 接口用的是内存数组,数据无法持久化。这一篇引入 Workers KV,一个全球分布式键值存储,让数据真正落地。

KV 是什么

KV 的全称是 Key-Value,就是一个超级大的 Map,通过键存取值

"user:1"  ->  {"name": "Alice", "age": 20}
"config"  ->  {"theme": "dark"}

它的特性如下

特性 说明
全球分布 数据自动复制到全球所有边缘节点
读写极快 读取由就近节点直接响应
最终一致性 写入后约 60 秒内传播到全球
支持过期时间 键可以设置 TTL,到期自动删除
单值上限 最大 25MB

KV 最适合读多写少的场景,典型用途是存储配置、功能开关、用户资料缓存、静态内容。

适用场景与注意点

KV 的最终一致性是新手最容易踩的坑。你在某个节点写入数据后,其他地区的节点可能要过一段时间才能读到新值。所以它不适合需要强一致性的业务,比如库存扣减、计数器、订单状态。

适合 KV 不适合 KV
站点配置 计数累加
用户资料缓存 库存扣减
静态内容 交易记录
功能开关 需要立刻读到最新值的场景

创建命名空间

KV 的数据存放在”命名空间”里,每个命名空间是一个独立的数据集合。一个 Worker 可以绑定多个命名空间。

用命令行创建

wrangler kv namespace create MY_KV

命令执行后输出类似

🌀 Creating namespace with title "worker-MY_KV"
✨ Success!
id = "e29b263ab50e42ce9b637fa8370175e8"

记下这个 id,也可以去仪表盘的 KV 页面创建,效果相同。

绑定到 Worker

在 wrangler.toml 中添加绑定配置

name = "my-worker"
main = "src/index.js"
compatibility_date = "2026-01-01"

[[kv_namespaces]]
binding = "MY_KV"
id = "e29b263ab50e42ce9b637fa8370175e8"

binding 是代码里的变量名,id 是刚创建的命名空间 id。配置后,代码里就可以用 env.MY_KV 访问。

基础读写删操作

export default {
  async fetch(request, env, ctx) {
    // 读取
    const value = await env.MY_KV.get("user:1");

    // 写入
    await env.MY_KV.put("user:1", JSON.stringify({ name: "Alice" }));

    // 删除
    await env.MY_KV.delete("user:1");

    // 按前缀列出键
    const list = await env.MY_KV.list({ prefix: "user:" });

    return Response.json({ value, list });
  },
};

常用方法一览

方法 说明
get(key) 读取值,不存在时返回 null
put(key, value) 写入或覆盖
delete(key) 删除
list(options) 按前缀等条件列出键
getWithMetadata(key) 读取值并附带元数据

KV 的值只能是字符串。存对象时用 JSON.stringify 序列化,读取时用 JSON.parse 反序列化。

数据过期设置

写入时可以设置过期时间,让 KV 自动清理数据

// 10 分钟(600 秒)后过期
await env.MY_KV.put("captcha:123", "abcd", { expirationTtl: 600 });

// 指定绝对过期时间戳
await env.MY_KV.put("promo", "summer", { expiration: 1790000000 });

expirationTtl 的单位是秒,从写入时刻开始计算。注意 TTL 有 60 秒的最小值。

接入上篇的 CRUD 接口

把上一篇的内存数组换成 KV,接口立刻变成持久化版本

export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);
    const parts = url.pathname.split("/").filter(Boolean);

    if (!(parts[0] === "api" && parts[1] === "users")) {
      return new Response("页面不存在", { status: 404 });
    }

    const id = parts[2];
    const method = request.method;

    // 读取单个用户
    if (method === "GET" && id) {
      const raw = await env.MY_KV.get(`user:${id}`);
      if (!raw) return Response.json({ error: "用户不存在" }, { status: 404 });
      return Response.json(JSON.parse(raw));
    }

    // 新增用户
    if (method === "POST") {
      const body = await request.json();
      const newId = String(Date.now());
      await env.MY_KV.put(`user:${newId}`, JSON.stringify(body));
      return Response.json({ id: newId, ...body }, { status: 201 });
    }

    // 删除用户
    if (method === "DELETE" && id) {
      await env.MY_KV.delete(`user:${id}`);
      return Response.json({ ok: true });
    }

    return Response.json({ error: "请求方式不支持" }, { status: 405 });
  },
};

键命名建议用前缀加分隔符,例如 user:1config:theme,方便用 list({ prefix: "user:" }) 按类型管理。

免费额度提醒

KV 免费计划按日计量,每天读 10 万次、写 1 千次、删除和列出各 1 千次。学习阶段用量很小,不用担心,但接口上线后要留意仪表盘的用量统计。

KV 解决了键值存储,但遇到需要 SQL 查询、关联表结构的场景就力不从心了。下一篇讲 D1 关系型数据库,并实现 KV 与 D1 搭配的缓存方案。

上一篇 Cloudflare Workers 环境变量与密钥管理
下一篇 Cloudflare Workers D1 数据库

上一篇
Cloudflare Workers 环境变量与密钥管理
下一篇
Cloudflare Workers D1 数据库