celld中文文档v0.6.2
GitHub ↗
服务 / 参考文档

R2

R2 是对象存储服务。Worker 通过 r2_buckets 绑定访问存储桶。celld 将对象存放在节点通过 --bucket 打开的集群存储桶中,因此 R2 的持久性取决于该对象存储。节点未配置集群存储桶时,所有 R2 方法都会失败。API 的详细说明请参阅 Workers API 参考。

示例#

R2 示例 演示如何在 R2 存储桶中读取、写入和删除对象。

wrangler.jsonc

json
{
  "name": "r2",
  "main": "index.js",
  "compatibility_date": "2026-01-01",
  "r2_buckets": [
    { "binding": "FILES", "bucket_name": "example-files" }
  ]
}

index.js

javascript
export default {
  async fetch(request, env) {
    const key = new URL(request.url).pathname.slice(1);
    if (!key) return new Response("Use /KEY.", { status: 400 });

    if (request.method === "PUT") {
      await env.FILES.put(key, request.body, {
        httpMetadata: {
          contentType: request.headers.get("content-type") ??
            "application/octet-stream",
        },
      });
      return new Response(null, { status: 204 });
    }

    if (request.method === "DELETE") {
      await env.FILES.delete(key);
      return new Response(null, { status: 204 });
    }

    if (request.method === "GET") {
      const object = await env.FILES.get(key);
      if (object === null) return new Response("Not found.", { status: 404 });

      const headers = new Headers();
      object.writeHttpMetadata(headers);
      headers.set("etag", object.httpEtag);
      return new Response(object.body, { headers });
    }

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

API#

  • get(key, { range, onlyIf }) 返回带有流式响应体的 R2ObjectBody,或返回 null。范围可通过 offset、length、suffix 或 Range 请求头指定。
  • head(key) 返回对象记录,不包含响应体。
  • put(key, value, { httpMetadata, customMetadata, onlyIf }) 接受字符串、ArrayBuffer、类型化数组、Blob 或 ReadableStream。条件不满足时返回 null。
  • delete(keys) 删除一个键或一组键。
  • list({ prefix, delimiter, cursor, startAfter }) 返回一页对象。
  • createMultipartUpload(key) 返回一个句柄。uploadPart(number, value) 上传一个分片,complete(parts) 将分片组装成对象。

键与存储#

每个绑定都有自己的 bucket_name。celld 将键 <key> 存储为对象 r2/<bucket_name>/<key>。键的长度为 1 至 1024 字节。流式 put() 的请求体超过 8 MiB 后会转为分片上传。delete() 每次最多删除 1000 个键。celld 没有公开存储桶 URL、预签名 URL 或 S3 端点;要公开提供这些内容,需要在前面设置一个 Worker。

对象存储会对部分键使用百分号编码:包括含有非 ASCII 字符、控制字符,或 % \ { } ^ ` [ ] " < > ~ # | * ? 中任意字符的键。例如,přehled.html 会变成 r2/<bucket_name>/p%C5%99ehled.html。每个空路径段变成 %,因此 photos/ 会变成 r2/<bucket_name>/photos/%。a/b、/a/b、a//b 和 a/b/ 是四个不同的对象,这与 Cloudflare R2 一致。list() 返回解码后的键,但按编码后的形式排序,并将 startAfter 与编码后的形式比较。Cloudflare R2 则按 UTF-8 字节排序。例如,Cloudflare R2 在 startAfter: "aa" 之后会返回 a~,但 celld 将 a%7E 与 aa 比较,因此会跳过该键。使用 celld 列表返回的 cursor 不会出现此问题。

如果 list() 遇到由其他工具写入、百分号解码后不是 UTF-8 的键,例如 a%FF,调用会失败。

celld 0.5.1 及更早版本会删除键中的所有空路径段。旧版本以 photos/ 写入的对象仍保存在 photos 下,list() 也会将其返回为 photos。

分片上传#

分片上传存在于创建它的节点上。分片规则请参阅分片上传文档。如果一个分片先于前面的分片到达,它会在内存中等待;等待中的分片总量最多为 256 MiB,达到上限后 celld 会拒绝更多分片。等待中的分片可以替换,已经写入对象存储的分片则不能替换,celld 会拒绝这种写入。

与 Cloudflare 的差异#

  • R2 绑定使用集群存储桶中的 r2/<bucket_name>/ 前缀。
  • 五个内容相关的 HTTP 头以对象头的形式存储。customMetadata、cacheExpiry、校验和与存储类别一起存为一个 JSON 值,用户元数据名称为 celld-r2;Azure Blob Storage 不允许元数据名称包含连字符,因此使用 celld_r2。
  • 其他工具写入的对象也可以通过绑定读取。其用户元数据成为 customMetadata,对象头成为 httpMetadata。要写入完整记录,请使用 celld r2 put。
  • celld r2 get|head|put|delete|list 替代 wrangler r2 object。命令直接读取集群存储桶,不需要正在运行的节点。
  • 对象的 version 等于内容 ETag,因此相同内容会得到相同版本。
  • 不支持 ssecKey 和 jurisdiction。
  • 条件写入不能使用大于 8 MiB 的流式请求体。
  • createMultipartUpload() 不接受校验和。
  • 分片上传无法在其他节点或重启后继续。celld 也无法替换对象存储中已经存在的分片。
  • 乱序分片最多占用 256 MiB 内存,完成上传时不能更改已存储分片的顺序。

Cloudflare 兼容性页面列出了运行时 API 和不支持的服务。

celld v0.6.2 · 简体中文文档
产品名、API、命令与示例代码保留原始写法。

输入关键词,搜索 20 篇中文文档。

支持中文术语、API 与环境变量 · Esc 关闭