Cloudflare R2 存储详细使用指南

Cloudflare R2 存储详细使用指南

解决方案goocz2025-05-15 18:06:123A+A-

Cloudflare R2 存储的详细使用指南。


Cloudflare R2 是一种与 Amazon S3 API 高度兼容的对象存储服务。它的主要卖点之一是**零出口(egress)费用**,这意味着您从 R2 下载数据到互联网时,Cloudflare 不会收取带宽费用(在合理使用范围内)。这使其成为存储大量数据、静态资源(如图片、视频、前端构建文件)以及与 Cloudflare Workers 集成的理想选择。


**核心概念:**


* **存储桶 (Buckets):** R2 中的基本存储容器。每个存储桶都有一个全局唯一的名称。您的对象(文件)存储在存储桶中。

* **对象 (Objects):** 您存储在 R2 中的文件(例如,图片、视频、文档、备份文件等)。每个对象都有一个唯一的键(key,即文件名或路径)和一个值(文件内容)。

* **键 (Key):** 对象在存储桶中的唯一标识符,类似于文件名或文件路径 (e.g., `images/profile.jpg`, `backup/2023-10-26.zip`)。

* **S3 兼容 API:** R2 实现了 Amazon S3 API 的一个子集,这意味着您可以使用许多现有的 S3 工具和 SDK 与 R2 交互。

* **零出口费用:** 从 R2 下载数据到公共互联网通常不收取带宽费用,这是相对于 AWS S3 等服务的一个显著优势。

* **与 Workers 集成:** R2 可以轻松地与 Cloudflare Workers 绑定,允许您通过边缘计算动态处理和提供存储在 R2 中的对象。


**详细使用指南:**


### 1. 准备工作


* **Cloudflare 账户:** 您需要一个 Cloudflare 账户。

* **Wrangler CLI (推荐):** Cloudflare 的命令行工具,用于管理 Workers 和 R2 存储桶(特别是与 Workers 集成时)。

* 安装: `npm install -g wrangler`

* 登录: `wrangler login`

* **S3 兼容工具 (可选):** 如 AWS CLI, rclone, Cyberduck, S3 Browser, 或各种编程语言的 S3 SDK。


### 2. 创建 R2 存储桶


您可以通过 Cloudflare 仪表板或 Wrangler CLI 创建 R2 存储桶。


* **通过 Cloudflare 仪表板:**

1. 登录到您的 Cloudflare 账户。

2. 在左侧导航栏中,找到并点击 "R2"。

3. 点击 "创建存储桶 (Create bucket)"。

4. 输入一个**全局唯一**的存储桶名称(例如 `my-unique-app-assets`)。

5. 选择存储桶的**存储位置提示 (Location Hint)**。这有助于 Cloudflare 将数据存储在靠近您预期访问模式的区域,但 R2 旨在提供全球访问。选择一个离您的主要用户或数据源近的位置。

6. 点击 "创建存储桶 (Create bucket)"。


* **通过 Wrangler CLI:**

```bash

wrangler r2 bucket create <YOUR_BUCKET_NAME> [--location-hint <HINT>]

```

例如:

```bash

wrangler r2 bucket create my-unique-app-assets --location-hint APAC

```

可用的位置提示 (Location Hints) 包括:`APAC` (亚太), `EEUR` (东欧), `ENAM` (北美东部), `WEUR` (西欧), `WNAM` (北美西部),或者留空让 Cloudflare 自动选择。


### 3. 配置 S3 API 访问 (用于第三方工具)


如果您想使用 S3 兼容的工具(如 AWS CLI, rclone)或 SDK 访问 R2,您需要生成 API 令牌。


1. 在 Cloudflare 仪表板的 R2 概览页面,点击 "管理 R2 API 令牌 (Manage R2 API Tokens)"。

2. 点击 "创建 API 令牌 (Create API token)"。

3. 给令牌一个描述性的名称。

4. 选择权限:

* **仅对象读取 (Object Read Only):** 只允许下载和列出对象。

* **对象读写 (Object Read & Write):** 允许上传、下载、列出、删除对象。

5. 选择要应用此令牌的存储桶(可以是特定存储桶或所有存储桶)。

6. (可选)设置 TTL(令牌有效期)。

7. 点击 "创建 API 令牌 (Create API token)"。

8. **立即复制并安全地保存 `访问密钥 ID (Access Key ID)` 和 `机密访问密钥 (Secret Access Key)`。机密访问密钥只显示一次。**


配置 S3 兼容工具时,您还需要您的**账户 ID (Account ID)**。您可以在 Cloudflare 仪表板的任何域的 "概述 (Overview)" 页面的右下角找到它,或者在 R2 页面的 "R2 API 令牌" 部分的顶部找到。


**S3 端点 (Endpoint):**

当配置 S3 工具时,您需要指定 R2 的 S3 API 端点。格式通常是:

`https://<ACCOUNT_ID>.r2.cloudflarestorage.com`


**示例:配置 AWS CLI**

```bash

aws configure --profile r2-profile

AWS Access Key ID [None]: YOUR_R2_ACCESS_KEY_ID

AWS Secret Access Key [None]: YOUR_R2_SECRET_ACCESS_KEY

Default region name [None]: auto # 或任何有效区域,例如 us-east-1,R2 会忽略它但 CLI 可能需要

Default output format [None]: json # 或 text, table


# 然后使用 --endpoint-url 和 --profile

aws s3 ls --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com --profile r2-profile

aws s3 ls s3://my-unique-app-assets --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com --profile r2-profile

aws s3 cp my-local-file.txt s3://my-unique-app-assets/my-remote-file.txt --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com --profile r2-profile

```


### 4. 使用 Wrangler CLI 与 R2 交互


Wrangler CLI 提供了直接与 R2 存储桶交互的命令,无需配置 S3 凭证(因为它使用您的 Cloudflare 登录会话)。


* **列出存储桶:**

```bash

wrangler r2 bucket list

```


* **上传对象:**

```bash

wrangler r2 object put <BUCKET_NAME>/<OBJECT_KEY> --file <PATH_TO_LOCAL_FILE> [--content-type <MIME_TYPE>]

```

例如:

```bash

wrangler r2 object put my-unique-app-assets/images/logo.png --file ./local/images/logo.png --content-type image/png

```


* **下载对象:**

```bash

wrangler r2 object get <BUCKET_NAME>/<OBJECT_KEY> --file <PATH_TO_SAVE_LOCALLY>

```

例如:

```bash

wrangler r2 object get my-unique-app-assets/images/logo.png --file ./downloaded-logo.png

```


* **列出对象:**

```bash

wrangler r2 object list <BUCKET_NAME> [--prefix <PREFIX>]

```

例如,列出 `images/` 目录下的所有对象:

```bash

wrangler r2 object list my-unique-app-assets --prefix images/

```


* **删除对象:**

```bash

wrangler r2 object delete <BUCKET_NAME>/<OBJECT_KEY>

# 或删除多个对象

wrangler r2 object delete <BUCKET_NAME>/<OBJECT_KEY_1> <BUCKET_NAME>/<OBJECT_KEY_2>

```

例如:

```bash

wrangler r2 object delete my-unique-app-assets/images/old-logo.png

```


* **删除存储桶 (存储桶必须为空):**

```bash

wrangler r2 bucket delete <BUCKET_NAME>

```


### 5. 将 R2 与 Cloudflare Workers 集成


这是 R2 最强大的用途之一。您可以将 R2 存储桶绑定到 Worker,然后在 Worker 代码中直接访问它。


1. **在 `wrangler.toml` 中配置绑定:**

在您的 Worker 项目的 `wrangler.toml` 文件中,添加一个 R2 存储桶绑定:

```toml

name = "my-worker-project"

main = "src/index.ts" # 或 .js

compatibility_date = "2023-10-30" # 使用较新的日期


# ... 其他配置 ...


[[r2_buckets]]

binding = "MY_BUCKET" # Worker 代码中将使用此名称访问 R2 存储桶

bucket_name = "my-unique-app-assets" # 您在 Cloudflare 上创建的 R2 存储桶的名称

# preview_bucket_name = "my-preview-bucket" # (可选) 用于 wrangler dev --remote 的预览存储桶

```

`binding`: 这是您在 Worker 代码中引用 R2 存储桶时将使用的变量名。


2. **在 Worker 代码中访问 R2:**

您的 Worker 脚本 (e.g., `src/index.ts`) 将通过 `env` 对象上的绑定名称访问 R2。


```typescript

// src/index.ts

export interface Env {

MY_BUCKET: R2Bucket; // 'MY_BUCKET' 必须与 wrangler.toml 中的 binding 名称匹配

}


export default {

async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {

const url = new URL(request.url);

const objectKey = url.pathname.slice(1); // 从路径获取对象键,例如 /my-image.png -> my-image.png


switch (request.method) {

case "PUT":

// 上传对象

if (!objectKey) {

return new Response("Object key is required in path", { status: 400 });

}

if (!request.body) {

return new Response("Request body is required for PUT", { status: 400 });

}

try {

const object = await env.MY_BUCKET.put(objectKey, request.body, {

httpMetadata: request.headers, // 复制客户端的 Content-Type, Content-Encoding 等

// customMetadata: { uploadedBy: "worker" }, // 可选的自定义元数据

});

return new Response(`Object ${object.key} uploaded successfully! Version: ${object.version}`, { status: 201 });

} catch (e: any) {

return new Response(`Error uploading object: ${e.message}`, { status: 500 });

}


case "GET":

// 获取对象

if (!objectKey) {

// 如果没有指定键,可以列出对象或返回错误

const options: R2ListOptions = {

prefix: url.searchParams.get('prefix') ?? undefined,

delimiter: url.searchParams.get('delimiter') ?? undefined,

cursor: url.searchParams.get('cursor') ?? undefined,

include: ['httpMetadata', 'customMetadata'], // 可选

};

const listing = await env.MY_BUCKET.list(options);

return new Response(JSON.stringify(listing), { headers: { 'content-type': 'application/json;charset=UTF-8' } });

}


const object = await env.MY_BUCKET.get(objectKey);


if (object === null) {

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

}


const headers = new Headers();

object.writeHttpMetadata(headers); // 设置 Content-Type, ETag 等

headers.set("etag", object.httpEtag);

// headers.set("Cache-Control", "public, max-age=3600"); // 可选:添加缓存头


return new Response(object.body, {

headers,

});


case "DELETE":

// 删除对象

if (!objectKey) {

return new Response("Object key is required for DELETE", { status: 400 });

}

try {

await env.MY_BUCKET.delete(objectKey);

return new Response(`Object ${objectKey} deleted successfully`);

} catch (e: any) {

return new Response(`Error deleting object: ${e.message}`, { status: 500 });

}


default:

return new Response("Method Not Allowed", { status: 405 });

}

},

};

```


**R2Bucket API 方法 (在 Worker 中):**

* `get(key: string, options?: R2GetOptions): Promise<R2Object | R2ObjectBody | null>`: 获取对象。

* `put(key: string, value: ReadableStream | ArrayBuffer | string | Blob, options?: R2PutOptions): Promise<R2Object>`: 上传对象。

* `httpMetadata`: 可以设置 Content-Type, Cache-Control 等 HTTP 头。

* `customMetadata`: 存储自定义键值对元数据。

* `delete(keys: string | string[]): Promise<void>`: 删除一个或多个对象。

* `list(options?: R2ListOptions): Promise<R2ListObjectsV2Output>`: 列出存储桶中的对象。

* `prefix`: 过滤具有特定前缀的对象。

* `delimiter`: 用于模拟目录结构。

* `cursor`: 用于分页。

* `limit`: 每页返回的对象数量。

* `head(key: string): Promise<R2Object | null>`: 获取对象的元数据而不下载其内容。

* `createMultipartUpload(key: string, options?: R2MultipartOptions): Promise<R2MultipartUpload>`: 开始分段上传(用于大文件)。

* `resumeMultipartUpload(key: string, uploadId: string): R2MultipartUpload`: 恢复分段上传。


### 6. 公开访问 R2 存储桶中的对象


默认情况下,R2 存储桶是私有的。您可以通过以下方式公开它们:


* **1. 通过自定义域名 (推荐):**

这是最灵活和推荐的方式,允许您使用自己的域名 (例如 `assets.yourdomain.com`) 来提供 R2 中的对象,并可以利用 Cloudflare 的缓存和其他功能。

1. 在 Cloudflare 仪表板中,转到您的域。

2. 在左侧导航栏中,找到 "R2"。

3. 在 R2 页面,找到您要公开的存储桶,点击其名称。

4. 转到 "设置 (Settings)" 标签页。

5. 在 "公共访问 (Public Access)" -> "通过 R2.dev 公开 (Public access via R2.dev)" 部分,点击 "允许访问 (Allow Access)"。**这会启用一个 `*.r2.dev` 的公共 URL,但通常您会想使用自己的域名。**

6. 在 "公共访问 (Public Access)" -> "连接的域 (Connected Domains)" 或 "自定义域 (Custom Domains)" 部分,点击 "连接域 (Connect Domain)" 或 "添加自定义域 (Add Custom Domain)"。

7. 输入您想用于访问此存储桶的子域名(例如 `r2-assets.yourdomain.com`)。Cloudflare 会自动为您处理 DNS 记录。

8. 一旦连接,`
https://r2-assets.yourdomain.com/object-key` 将公开提供对象。

9. 您可以配置缓存规则、转换规则等作用于此子域名。


* **2. 通过 `*.r2.dev` 公共 URL (谨慎使用):**

当您在存储桶设置中启用 "通过 R2.dev 公开 (Public access via R2.dev)" 时,您的存储桶会获得一个公共 URL,格式为 `https://pub-<RANDOM_ID>.r2.dev`。

* 您可以在存储桶的设置页面找到这个 URL。

* 对象可以通过 `https://pub-<RANDOM_ID>.r2.dev/object-key` 访问。

* **注意:** 此 URL 是公开的,任何知道它的人都可以访问您的对象。它不直接与您的 Cloudflare 区域 (zone) 绑定,因此缓存等功能可能不像自定义域那样直接可配置。


* **3. 通过 Worker (完全控制):**

如上面的 Worker 示例所示,您可以编写一个 Worker 来从 R2 获取对象并将其作为 HTTP 响应返回。这使您可以实现自定义授权、内容转换等。


### 7. 预签名 URL (Presigned URLs)


预签名 URL 允许您为私有对象生成一个临时的、有时间限制的公共访问链接。这对于允许用户临时下载或上传特定对象非常有用,而无需公开整个存储桶或管理复杂的用户权限。


* **在 Worker 中生成预签名 URL:**

```typescript

// src/index.ts (部分示例)

export interface Env {

MY_BUCKET: R2Bucket;

}


export default {

async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {

const url = new URL(request.url);

const objectKey = "private/document.pdf"; // 假设这是您要为其生成链接的对象


if (url.pathname === "/generate-download-link") {

try {

const signedUrl = await env.MY_BUCKET.createSignedUrl('getObject', objectKey, {

// S3 兼容的 API 操作: 'getObject', 'putObject'

// expires: 3600, // URL 有效期(秒),默认 3600 (1小时)

// Можно также указать другие параметры, такие как `range`, `contentDisposition` и т.д.

});

return new Response(JSON.stringify({ downloadUrl: signedUrl }), {

headers: { "Content-Type": "application/json" },

});

} catch (e: any) {

return new Response(`Error generating signed URL: ${e.message}`, { status: 500 });

}

}

// ... 其他路由 ...

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

},

};

```

然后,客户端可以使用此 `signedUrl` 在有效期内下载对象。


### 8. 定价


R2 的定价通常基于:


* **存储量:** 每月存储的数据总量 (GB)。

* **A 类操作 (Class A Operations):** 主要是写入和列出操作 (如 PUT, LIST, COPY)。

* **B 类操作 (Class B Operations):** 主要是读取操作 (如 GET, HEAD)。


**关键优势:零出口费用。**

Cloudflare 通常会提供一个免费套餐,包含一定量的存储和操作数。超出部分按使用量计费。请务必查阅 [Cloudflare R2 官方定价页面] 以获取最新和最准确的信息。


### 9. 最佳实践和注意事项


* **存储桶命名:** 使用有意义且符合 DNS 命名约定的存储桶名称。

* **对象键命名:** 使用 `/` 来模拟目录结构,方便组织和列出对象 (例如 `
images/avatars/user123.jpg`)。

* **安全性:**

* 默认情况下存储桶是私有的。仅在必要时公开访问。

* 优先使用自定义域进行公共访问,以便更好地控制和集成 Cloudflare 功能。

* 安全地管理您的 R2 API 令牌。为不同的应用程序或用途使用具有最小必要权限的不同令牌。

* 对于临时访问,请使用预签名 URL。

* **内容类型 (Content-Type):** 上传对象时,设置正确的 `Content-Type` HTTP 头 (MIME 类型),以便浏览器能正确处理文件。Wrangler 和 Worker 的 `put` 方法都允许您设置它。

* **缓存:** 如果通过自定义域公开 R2 对象,请配置 Cloudflare 缓存规则以提高性能并减少对 R2 的直接请求。

* **错误处理:** 在 Worker 代码中妥善处理 R2 API 调用可能发生的错误。

* **大文件上传:** 对于非常大的文件,考虑使用分段上传 (Multipart Uploads)。Worker 中的 `createMultipartUpload` 方法支持此功能,许多 S3 SDK 和工具也支持。

* **数据一致性:** R2 提供强最终一致性。在写入新对象或覆盖/删除现有对象后,后续的读取操作(包括GET、HEAD和LIST)将立即反映这些更改。

* **版本控制 (Versioning):** R2 支持对象版本控制。您可以在存储桶设置中启用它。启用后,对对象的每次修改(上传新版本或删除)都会创建一个新版本,而不是直接覆盖或永久删除。这有助于防止意外删除或覆盖,并允许您恢复到对象的先前版本。

* **对象生命周期管理 (Object Lifecycle Management):** R2 支持生命周期规则,允许您自动管理对象。例如,您可以设置规则在对象达到一定年龄后将其删除,或者(如果未来支持)将其转移到不同的存储类别。


### 10. 总结


Cloudflare R2 是一个强大且经济高效的对象存储解决方案,特别是当您需要处理大量数据出口或希望与 Cloudflare 生态系统(尤其是 Workers)紧密集成时。其 S3 兼容性使其易于采用,而零出口费用是一个巨大的吸引力。


请始终参考 [Cloudflare R2 官方文档] 以获取最新的功能、限制和最佳实践信息。

点击这里复制本文地址 以上内容由goocz整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

果子教程网 © All Rights Reserved.  蜀ICP备2024111239号-5