保持线上与本地开发环境数据一致性

将线上的 Cloudflare R2(对象存储,用于存图片等文件)和 D1(数据库,用于存文章标题、内容等元数据)的数据导入到本地,以确保开发环境与生产环境一致,主要涉及两个部分:

同步 R2 中的文件(图片等)

同步 D1 中的数据库记录,并更新文件链接

下面我将为你提供一个完整、分步的指南。

核心概念:D1 与 R2 的关系

在你的应用中:

Cloudflare D1 存储的是结构化数据,比如你的 posts 表,里面有 id, title, content, slug 以及一个 image_url 字段。

Cloudflare R2 存储的是对象文件,也就是用户上传的图片。D1 数据库中的 image_url 字段,其值就是指向 R2 中对应图片文件的 URL。

要做到数据一致,我们必须同时处理这两部分。

准备工作:安装与登录

确保你已经安装了 Cloudflare 的命令行工具 wrangler,并且已经登录。

Generated bash

安装/更新 wrangler

npm install -g wrangler

登录你的 Cloudflare 账户

wrangler login

步骤一:从线上的 R2 Bucket 下载所有图片

首先,我们需要把生产环境 R2 Bucket 里的所有图片文件下载到本地的一个文件夹里。

找到你的 R2 Bucket 名称:登录 Cloudflare 控制台,进入 "R2" 页面,找到你的存储桶名称,例如 my-blog-images-prod。

在本地创建一个文件夹:用于存放下载下来的图片。

Generated bash

mkdir -p local-r2-data

IGNORE_WHEN_COPYING_START

content_copy

download

Use code with caution.

Bash

IGNORE_WHEN_COPYING_END

使用 wrangler 下载文件:运行以下命令,它会将指定 R2 Bucket 中的所有文件下载到你刚创建的本地文件夹中。

Generated bash

语法: wrangler r2 bucket download <BUCKET_NAME> [LOCAL_DIRECTORY]

示例:

wrangler r2 bucket download my-blog-images-prod ./local-r2-data

IGNORE_WHEN_COPYING_START

content_copy

download

Use code with caution.

Bash

IGNORE_WHEN_COPYING_END

执行后,local-r2-data 文件夹里现在就有了所有线上的图片。

步骤二:为本地图片创建一个本地服务

现在图片在本地了,但你的本地应用需要通过一个 HTTP URL (如 http://localhost:8788/images/xxx.png) 来访问它们,而不是通过文件路径。我们有两种主流方案:

方案 A:使用本地 S3 兼容服务器 (推荐,更接近真实环境)

使用像 MinIO 这样的工具,可以在本地模拟一个和 R2 (S3-compatible) 一样的对象存储服务。

使用 Docker 运行 MinIO (最简单的方式):

Generated bash

docker run \

-p 9000:9000 \

-p 9001:9001 \

--name minio \

-e "MINIO_ROOT_USER=my-access-key" \

-e "MINIO_ROOT_SECRET=my-secret-key" \

minio/minio server /data --console-address ":9001"

IGNORE_WHEN_COPYING_START

content_copy

download

Use code with caution.

Bash

IGNORE_WHEN_COPYING_END

这会在本地 9000 端口启动 MinIO 服务,9001 端口启动管理后台。

访问 http://localhost:9001,用上面设置的 my-access-key 和 my-secret-key 登录。

在 MinIO 中创建 Bucket 并上传文件:

在 MinIO 管理后台,创建一个 Bucket,例如 dev-bucket。

进入这个 Bucket,点击 "Upload",然后将 local-r2-data 文件夹里的所有文件上传上去。

配置本地应用: 在你的本地开发环境 (.dev.vars 或 wrangler.toml 的 dev 部分) 中,需要配置环境变量,告诉应用去连接本地的 MinIO 而不是线上的 R2。

Generated ini

.dev.vars

R2_BUCKET_NAME="dev-bucket"

S3_ENDPOINT="http://127.0.0.1:9000" # MinIO 地址

S3_ACCESS_KEY_ID="my-access-key"

S3_SECRET_ACCESS_KEY="my-secret-key"

你需要修改你的应用代码,在开发模式下使用这些S3客户端配置

IGNORE_WHEN_COPYING_START

content_copy

download

Use code with caution.

Ini

IGNORE_WHEN_COPYING_END

方案 B:使用简单的静态文件服务器 (简单快捷)

如果不想配置 MinIO,可以把图片文件夹当作静态资源,用一个简单的服务器来托管。

将图片文件夹放在 public 目录下:

将下载好的 local-r2-data 文件夹移动到你项目根目录下的 public 文件夹中,并重命名为 uploads。你的目录结构看起来像:public/uploads/image1.jpg。

修改本地开发服务器配置:

Cloudflare Workers 本地开发服务器 wrangler dev 默认会托管 public 目录下的静态资源。所以,现在你可以通过 http://localhost:8787/uploads/image1.jpg 访问到这个图片 (端口号以你的实际情况为准)。

步骤三:同步 D1 数据库并更新 URL

这是最关键的一步,我们需要把线上的数据库内容导到本地,并把里面的 image_url 从线上地址改成我们本地的地址。

找到你的 D1 数据库名称:在 wrangler.toml 文件中找到生产环境的 database_name。例如 prod-db。

从线上 D1 导出数据: 运行命令,将线上数据库导出为一个 .sql 文件。

Generated bash

语法: wrangler d1 export <DATABASE_NAME> --output=./dump.sql

示例:

wrangler d1 export prod-db --output=./prod_dump.sql

IGNORE_WHEN_COPYING_START

content_copy

download

Use code with caution.

Bash

IGNORE_WHEN_COPYING_END

修改 SQL 文件中的 URL:

打开 prod_dump.sql 文件。你需要批量替换 image_url 字段的值。

原 URL 格式: https://<your-r2-public-url>/image1.jpg

目标 URL 格式 (方案A-MinIO): http://localhost:9000/dev-bucket/image1.jpg

目标 URL 格式 (方案B-静态服务器): /uploads/image1.jpg (使用相对路径更佳)

你可以使用任何文本编辑器的“查找和替换”功能。例如,将 https://<your-r2-public-url>/ 替换为 /uploads/。

将修改后的数据导入本地 D1:

首先,确保你的 wrangler.toml 中为本地开发环境配置了 D1 数据库。

Generated toml

wrangler.toml

[[d1_databases]]

binding = "DB"

database_name = "local-dev-db"

database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" # 本地数据库ID

preview_database_id = "..." # 预览环境ID

IGNORE_WHEN_COPYING_START

content_copy

download

Use code with caution.

Toml

IGNORE_WHEN_COPYING_END

然后,执行导入命令,将修改后的 SQL 文件导入到本地 D1 数据库。

Generated bash

语法: wrangler d1 execute <DATABASE_NAME> --local --file=./path/to/sql

示例:

wrangler d1 execute local-dev-db --local --file=./prod_dump.sql

IGNORE_WHEN_COPYING_START

content_copy

download

Use code with caution.

Bash

IGNORE_WHEN_COPYING_END

--local 标志是关键,它确保了数据是写入本地的 .wrangler/state/d1 目录下的 SQLite 文件,而不是线上数据库。

总结与推荐流程

对于大多数项目,方案 B (静态文件服务器) 是最快、最简单的。

完整流程回顾 (使用方案 B):

下载 R2 文件:

wrangler r2 bucket download my-blog-images-prod

移动并重命名文件:

将下载好的文件夹移动到项目 public 目录下,并重命名为 uploads。

导出线上 D1 数据:

wrangler d1 export prod-db --output=./prod_dump.sql

修改 SQL 文件:

打开 prod_dump.sql,全局查找替换图片 URL 的前缀。例如,将 https://pub-xxxxx.r2.dev/ 替换为 /uploads/。

导入到本地 D1:

wrangler d1 execute local-dev-db --local --file=./prod_dump.sql

启动本地开发:

wrangler dev

现在,你的本地开发环境就拥有了和线上几乎完全一致的数据,图片和数据库记录都已同步并正确链接。