在这篇文章中,我们将从创建第一个 D1 数据库开始,一步步构建一个由 Cloudflare Pages 驱动前端D1 数据库提供后端支持的全栈应用。我们将详细解析 wrangler.toml 的每一项配置,阐明本地开发和云端部署的核心命令,并揭示那些导致“表不存在”或“部署失败”等常见问题的根本原因。

性能对比总结表

特性 Cloudflare Pages + D1 Go + Gin (传统 VPS) 纯静态网站
访问速度 (TTFB) 静态部分极快,动态部分快 区域内快,全球慢 极致快
数据延迟 (DB Query) 好,但受限于区域 区域内极好 不适用
可伸缩性/并发 极高 (自动弹性伸缩) 有限 (需手动扩容) 极高 (CDN 天然优势)
冷启动 有 (但极短) 无 (进程常驻)
运维复杂度 极低 (Serverless) 高 (需管理服务器系统安全) 极低
开发体验 现代,前后端分离 成熟,一体化或分离均可 简单,但受限
成本 起步极低,按量付费 固定月费,随流量增长 极低

核心理念:理解两个独立的环境

在开始之前,最重要的一点是理解:你的本地开发环境和你部署到的 Cloudflare 云端环境是完全隔离的。

  • 本地环境:所有文件数据库 (.wrangler 目录下的 .sqlite 文件) 都存储在你的电脑上。
  • 云端环境:代码和静态文件部署在全球网络上,连接的是一个完全独立的在云端的 D1 数据库。

你在本地对数据库做的任何修改(比如创建表),都不会自动同步到云端,反之亦然。这是所有问题的根源。

以下是 D1 的免费额度:

功能 (Feature) 免费额度  说明
数据库总数 (Total Databases) 10 个 你的 Cloudflare 账户可以创建的数据库实例总数。
数据库存储空间 (Database Storage) 5 GB 你所有 D1 数据库占用的磁盘空间总和。
每天读取行数 (Rows Read per Month) 500 万次 所有 SELECT 等读操作访问的行数总和。
每天写入行数 (Rows Written per Month) 10 万次 所有 INSERT UPDATE DELETE 等写操作影响的行数总和。

第零步:创建你的 D1 数据库

在编写任何代码之前,我们首先需要在 Cloudflare 上拥有一个 D1 数据库。这可以通过 Wrangler CLI 方便地完成。

  1. 打开你的项目终端

  2. 运行创建命令
     

    #安装wrangler 
    npm install wrangler 
    # 语法: wrangler d1 create <DATABASE_NAME>
    wrangler d1 create blog
    
  3. 保存输出结果:命令执行成功后,Wrangler 会返回一段 wrangler.toml 配置代码。这段代码至关重要,请立即将它复制下来。

    它看起来会是这样:

    [[d1_databases]]
    binding = "DB" # 这个名字可以自定义,但建议保持 "DB"
    database_name = "blog"
    database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    

    这里的 database_id 是 Cloudflare 为你的数据库生成的唯一标识符。

现在,你已经在云端拥有了一个名为 blog 的空数据库。接下来,我们将在项目配置中引用它。

第一步:奠定基石 - wrangler.toml 配置详解

wrangler.toml 是你项目的指挥中心。在项目根目录下创建(或修改)这个文件,并将我们刚才获得的配置粘贴进去,然后补充其他必要信息。

# wrangler.toml

# 1. 基本信息
# 你的 Cloudflare Pages 项目名称,会显示在仪表盘上
name = "my-d1-blog"
# Pages Functions 的入口文件,对于中间件模式,通常是这个
main = "functions/_middleware.js" 

# 2. 兼容性设置
# 确保你的代码在特定版本的 Workers 运行时上行为一致
compatibility_date = "2024-03-01"

# 3. 账户信息
# 你的 Cloudflare 账户 ID
account_id = "YOUR_ACCOUNT_ID" # 替换成你自己的 Account ID

# 4. Pages 构建配置
[pages_build]
# Cloudflare 构建项目时运行的命令,用于生成静态文件
build = "go run generate_static.go"
# 构建命令生成的静态文件的输出目录
build_output_dir = "dist"

# 5. D1 数据库绑定(将刚才创建数据库时复制的内容粘贴到这里,并进行补充)
[[d1_databases]]
# 绑定变量名:在你的 Function 代码中,通过 env.DB 访问数据库
binding = "DB" 
# 数据库名称:在 Cloudflare 仪表盘中显示的名称
database_name = "blog"
# 数据库的唯一ID (从创建命令的输出中获取)
database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" # 替换成你自己的 Database ID
# 【关键】预览/本地数据库ID:确保本地开发时也使用这个ID对应的数据库
# 直接复制上面的 database_id 即可
preview_database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" # 替换成你自己的 Database ID
# 数据库迁移文件(SQL schema)所在的目录
migrations_dir = "d1/migrations"

配置项深度解析:

  • account_id 如何获取?

    1. 登录 Cloudflare 仪表盘。
    2. 在主页的右侧边栏,找到并点击 "Workers & Pages"
    3. 在 "Workers & Pages" 概览页面的右侧,你会看到你的 账户 ID (Account ID)。直接点击复制即可。

 

  • [[d1_databases]] 为何如此重要?
    这部分就是你项目的“地址簿”,它告诉 Wrangler:

    • binding = "DB":在代码里,请创建一个名为 DB 的变量。
    • database_name = "blog"database_id = "...":这个 DB 变量应该连接到名为 blogID 为 ... 的那个云端 D1 数据库。
    • preview_database_id = "..."这是解决本地开发问题的关键! 它明确告诉 Wrangler,当运行本地开发服务器 (wrangler pages dev) 时,也应该使用与这个 ID 关联的持久化本地数据库文件,而不是创建一个临时的内存数据库。
    • migrations_dir = "...":当运行迁移命令时,请到这个目录里寻找 SQL 文件。

第二步:本地开发 - 正确的命令与错误的陷阱

本地开发流程分为两步:准备数据库和启动服务。

1. 准备本地数据库 (wrangler d1 migrations apply)

这个命令用来在你的本地数据库中创建表索引等结构。

# --local 标志是关键,表示在本地操作
wrangler d1 migrations apply blog --local

Migrations to be applied:
┌──────────────────────────┐
│ name                     │
├──────────────────────────┤
│ 0001_create_articles.sql │
└──────────────────────────┘
√ About to apply 1 migration(s)
Your database may not be available to serve requests during the migration, continue? ... yes
🌀 Executing on local database blog (3d8df471-0e35-457a-a43e-915fe6e0a920) from .wrangler\state\v3\d1:
🌀 To execute on your remote database, add a --remote flag to your wrangler command.
🚣 5 commands executed successfully.
┌──────────────────────────┬────────┐
│ name                     │ status │
├──────────────────────────┼────────┤
│ 0001_create_articles.sql │ ✅     │
└──────────────────────────┴────────┘

它做了什么?

  1. 读取 wrangler.toml,找到 database_name = "blog" 的配置。
  2. 在你的项目下找到 .wrangler/state/v3/d1 目录,并定位到与 preview_database_id 匹配的那个 .sqlite 文件。如果不存在,则会创建。
  3. 读取 migrations_dir 指定目录下的所有 SQL 文件。
  4. 在那个 .sqlite 文件中执行这些 SQL 语句,创建你的表。

2. 启动本地开发服务 (wrangler pages dev)

现在,启动你的本地服务器来预览整个应用。

✅ 正确的命令:

wrangler pages dev dist

它做了什么?

  1. 读取 wrangler.toml
  2. 看到 [pages_build] 配置,它会自动运行 go run generate_static.go 来确保 dist 目录是最新的。
  3. 启动一个本地服务器,托管 dist 目录的静态文件。
  4. 看到 [[d1_databases]] 配置,它会自动将 env.DB 绑定到由 preview_database_id 确定的同一个本地数据库文件。
  5. 你的应用现在可以愉快地读写那个已经创建好表的本地数据库了。

❌ 错误的陷阱:

# 这是一个非常常见的错误命令!
wrangler pages dev dist --d1=DB

它做了什么?
--d1=DB 这个标志是一个覆盖指令。它告诉 Wrangler:“忽略 wrangler.toml 里所有关于 D1 的配置!现在,立即为我创建一个全新的空的临时的只存在于内存中的 D1 数据库,并把它绑定给 DB 变量。

后果:你的应用连接到了一个空数据库,当它执行 SELECT * FROM articles 时,自然就会抛出 D1_ERROR: no such table: articles 的错误。

第三步:部署到云端 - 连接真实世界

本地开发完美后,就可以部署了。记住,云端是一个全新的空的环境。

1. 准备云端数据库 (wrangler d1 migrations apply --remote)

你需要把你的数据库表结构应用到云端的真实的 D1 数据库上。

# --remote 标志是关键,表示在云端操作
wrangler d1 migrations apply blog --remote

它做了什么?
这个命令和本地版本类似,但它会使用你的 Cloudflare API 凭据,连接到云端那个真实的 blog 数据库,并在其中执行迁移 SQL。这是一个一次性的设置步骤(除非将来你需要修改表结构)。

2. 在 Cloudflare 仪表盘上确认绑定

这是最容易被忽略,也最致命的一步。你需要确保你的 Pages 项目被授权访问 D1 数据库。

  1. 登录 Cloudflare 仪表盘 -> Workers & Pages
  2. 点击你的 Pages 项目 (例如 my-d1-blog),而不是 D1 数据库。
  3. 进入 "设置" (Settings) -> "函数" (Functions)
  4. 向下滚动到 "D1 数据库绑定" (D1 database bindings)
  5. 确认或添加一条绑定:
    • 变量名称 (Variable name): DB
    • D1 数据库 (D1 database): blog
  6. 点击 "保存"

这一步在 wrangler.toml 和你的云端项目之间建立了最终的连接。

3. 部署应用

现在万事俱备,只需部署即可。

  • 通过 Git (推荐):如果你连接了 Git 仓库,只需 git push 即可。Cloudflare 会自动构建和部署。

  • 通过 Wrangler CLI

    wrangler pages deploy dist
    

Your Worker has access to the following bindings:
Binding                                            Resource         Mode
env.DB (3d8df471-0e35-457a-a43e-915fe6e0a920)      D1 Database      local

╭──────────────────────────────────────────────────────────────────────╮
│  [b] open a browser [d] open devtools [c] clear console [x] to exit  │
╰──────────────────────────────────────────────────────────────────────╯
⎔ Starting local server...
[wrangler:info] Ready on http://127.0.0.1:8788

 

备份d1数据库

查看数据库

 wrangler d1 list

 ⛅️ wrangler 4.27.0

uuid name created_at version num_tables file_size
3d8df471-XXX blog 2025-08-04T07:07:40.758Z production 0 28672
89570ac6-XXX diary 2025-05-23T09:37:59.459Z production 0 12288

备份(需要在wrangler.toml同目录下)

wrangler d1 export blog --output backup.sql

🌀 Exporting local database blog (3d8df471-0e35-457a-a43e-915fe6e0a920) from .wrangler\state\v3\d1:
🌀 To export your remote database, add a --remote flag to your wrangler command.
🌀 Exporting SQL to backup.sql...
Done!

 

结论与排错清单

 

如果再遇到问题,请对照以下清单进行排查:

  1. wrangler.toml 是否正确?

    • account_iddatabase_id 是否正确填写?
    • 是否已添加 preview_database_id
  2. 本地开发问题?

    • 是否运行了 wrangler d1 migrations apply blog --local
    • 启动命令是否是不带 --d1 标志的 wrangler pages dev dist
    • 是否尝试过删除 .wrangler 目录并重新运行迁移?
  3. 云端部署失败?

    • 是否运行了 wrangler d1 migrations apply blog --remote
    • 是否在 Pages 项目的设置 -> 函数 中手动检查并确认了 D1 绑定?
    • 是否查看了 Cloudflare 仪表盘中的部署日志以获取具体的错误信息?