上手 Cloudflare D1:无服务器数据库入门与博客实战
概述
Cloudflare D1 是 Cloudflare 推出的无服务器 SQLite 数据库,基于 SQLite 构建,天然与 Cloudflare Workers 集成。它让你在边缘节点直接读写关系型数据,无需管理服务器,无需操心连接池,按需付费。
核心特性
- SQLite 兼容:标准 SQL 语法,零学习成本
- 边缘读取:数据在全球节点缓存,读请求毫秒级响应
- 按需付费:无闲置费用,只有读写操作收费
- 与 Workers 深度集成:通过
env.DB直接调用,无需 HTTP 请求 - 内置备份与回滚:自动备份,支持时间点恢复
免费额度
| 项目 | 额度 |
|---|---|
| 数据库数量 | 50,000 个 |
| 每个数据库大小 | 500 MB |
| 读行数 | 50 亿行/月 |
| 写行数 | 1 亿行/月 |
| 存储 | 5 GB(超出 $0.001/GB/月) |
对于个人博客来说,这个免费额度绰绰有余。
需求分析
为什么我的博客需要 D1?因为几个我想要的功能都需要数据库支撑:
- 登录/注册 — 用户管理与评论者身份识别
- 文章浏览数 — 记录每篇文章的 PV
- 聊天室 — 实时消息存储
- 评论功能 — 文章评论持久化
没有数据库之前,这些数据只能靠前端 LocalStorage 或远端 JSON 文件模拟,既不安全也无法跨设备同步。D1 提供了轻量级关系型数据库的能力,正好填补这个空缺。
下面以登录功能为例,演示 D1 从创建到使用到接入的完整流程。
一、创建 D1 数据库
进入 Cloudflare Dashboard → Storage & Databases → D1 SQLite Database,点击 Create。

填写数据库名称(例如 blog-database),创建成功后你会得到一个 database_id:
c7e2f4b1-9937-4c7f-acd6-46aea0cb0504

记住这个 ID,后面两种操作方式都会用到它。
二、搭建用户表
在写代码之前,先设计好表结构。以用户表为例,完整的建表语句如下:
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE,
email TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
avatar_url TEXT DEFAULT '',
bio TEXT DEFAULT '',
role TEXT DEFAULT 'user' CHECK(role IN ('user', 'admin')),
created_at TEXT DEFAULT (datetime('now')),
updated_at TEXT DEFAULT (datetime('now'))
);
字段说明:
| 字段 | 说明 |
|---|---|
| id | 自增主键 |
| username | 用户名,唯一 |
| 邮箱,唯一,可用于登录 | |
| password_hash | 密码哈希值(绝不存明文) |
| avatar_url | 头像链接 |
| bio | 个人简介 |
| role | 角色:user 普通用户 / admin 管理员 |
| created_at | 注册时间 |
| updated_at | 更新时间 |
三、方式一:REST API 操作(Python)
如果你博客后端是 Python(Django、Flask 等),可以通过 D1 的 REST API 直接操作数据库。
1. 获取 Account ID
进入 Cloudflare Dashboard 首页,点击右侧右上角的三点菜单 → 复制 Account ID。

2. 创建 API Token
进入 My Profile → API Tokens → Create Token,选择 Edit Cloudflare Workers 模板,权限至少包含 D1: Edit。
3. 操作演示
import requests
ACCOUNT_ID = "你的Account ID"
DATABASE_ID = "你的database_id"
API_TOKEN = "你的API Token"
url = f"https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/d1/database/{DATABASE_ID}/query"
headers = {
"Authorization": f"Bearer {API_TOKEN}",
"Content-Type": "application/json"
}
# 创建表
sql = """
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL
)
"""
res = requests.post(url, headers=headers, json={"sql": sql})
print(res.json()["success"]) # True 即创建成功
# 插入数据(使用 ? 占位符防 SQL 注入)
sql = "INSERT INTO users (name, email) VALUES (?, ?)"
params = ["Alice", "alice@example.com"]
res = requests.post(url, headers=headers, json={"sql": sql, "params": params})
print(res.json()["success"])
# 查询数据
sql = "SELECT * FROM users WHERE email = ?"
params = ["alice@example.com"]
res = requests.post(url, headers=headers, json={"sql": sql, "params": params})
data = res.json()
if data["success"]:
print(data["result"][0]["results"])
4. 验证
在 Dashboard 的 D1 页面,可以直观看到数据:

也可以点 Console 直接运行 SQL 查看结果:

四、方式二:Worker 绑定操作(推荐)
为什么推荐?
- 零网络延迟:
env.DB是 Worker 内部绑定,不走 HTTP - 无需管理 API Token:绑定由 Cloudflare 证书自动处理,零泄露风险
- 原生 TypeScript 支持:
prepare().bind()天然防 SQL 注入 - 与 Pages Functions 集成:博客和 API 可同域部署
1. wrangler.jsonc 配置
{
"d1_databases": [
{
"binding": "DB",
"database_name": "blog-database",
"database_id": "c7e2f4b1-9937-4c7f-acd6-46aea0cb0504"
}
]
}
binding名称(这里是DB)后面通过env.DB访问。
2. Worker 操作演示
export default {
async fetch(request: Request, env: { DB: D1Database }): Promise<Response> {
try {
// 创建表
await env.DB.exec(
"CREATE TABLE IF NOT EXISTS posts (" +
" id INTEGER PRIMARY KEY AUTOINCREMENT," +
" title TEXT," +
" views INTEGER DEFAULT 0," +
" created_at TEXT DEFAULT (datetime('now'))" +
")"
);
// 插入数据(参数化查询)
await env.DB
.prepare("INSERT INTO posts (title) VALUES (?)")
.bind("我的第一篇博客")
.run();
// 查询数据
const { results } = await env.DB
.prepare("SELECT * FROM posts ORDER BY id DESC LIMIT 10")
.all();
return new Response(JSON.stringify({ code: 1, data: results }), {
headers: { "content-type": "application/json" },
});
} catch (e: any) {
return new Response(JSON.stringify({ code: 0, error: e.message }), {
headers: { "content-type": "application/json" },
});
}
},
};
3. D1 常用操作速查
// 单条查询 - 返回第一行
const user = await DB.prepare("SELECT * FROM users WHERE id = ?").bind(1).first();
// 多条查询 - 返回所有行
const { results } = await DB.prepare("SELECT * FROM users").all();
// 写入 - 返回执行结果
const { success, meta } = await DB
.prepare("INSERT INTO users (name, email) VALUES (?, ?)")
.bind("Bob", "bob@example.com")
.run();
// 批量写入
const insert = DB.prepare("INSERT INTO users (name, email) VALUES (?, ?)");
await DB.batch([
insert.bind("Alice", "alice@example.com"),
insert.bind("Bob", "bob@example.com"),
]);
五、实战:用 D1 写一个登录接口
回到最开始的需求,用 Worker + D1 实现登录其实只需要三个核心步骤:
1. 建表(sessions 表)
CREATE TABLE IF NOT EXISTS sessions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
token TEXT NOT NULL UNIQUE,
expires_at TEXT NOT NULL,
created_at TEXT DEFAULT (datetime('now')),
FOREIGN KEY (user_id) REFERENCES users(id)
);
2. 登录逻辑(仅展示核心 D1 操作)
// 注册:将用户数据写入 D1
await DB
.prepare("INSERT INTO users (username, email, password_hash) VALUES (?, ?, ?)")
.bind(username, email, hashedPassword)
.run();
// 登录:从 D1 查询用户
const user = await DB
.prepare("SELECT * FROM users WHERE username = ? OR email = ?")
.bind(login, login)
.first();
// 验证通过后,向 D1 写入 session token
await DB
.prepare("INSERT INTO sessions (user_id, token, expires_at) VALUES (?, ?, ?)")
.bind(user.id, token, expiresAt)
.run();
// 鉴权:从 D1 校验 token
const session = await DB
.prepare(`
SELECT u.id, u.username, u.email, u.role
FROM sessions s JOIN users u ON u.id = s.user_id
WHERE s.token = ? AND s.expires_at > datetime('now')
`)
.bind(token)
.first();
本质上就是在 D1 里读写三条 SQL 语句——注册一条 INSERT、登录一条 SELECT + 一条 INSERT、鉴权一条 JOIN 查询。这就是 D1 的典型用法。
3. 小技巧:用 Workflow 定时清理过期 session
// 在 Worker 中添加定时任务,每天清理一次过期 session
async function cleanExpiredSessions(DB: D1Database) {
const { meta } = await DB
.prepare("DELETE FROM sessions WHERE expires_at <= datetime('now')")
.run();
console.log(`清理了 ${meta.changes} 条过期 session`);
}
总结
D1 解决了博客对关系型数据库的需求,而 Workers 绑定让它用起来像本地变量一样简单:
- 建库:Dashboard 点两下即可
- 建表:标准 SQL,无需学习新语法
- 读写:REST API 适合外部服务,Worker 绑定零延迟
- 扩展:登录 → 文章浏览数 → 评论 → 聊天室,一个 D1 搞定所有
相关文档
📝 本文发布于 栏轩·阁
🌐 欢迎关注我的其他平台:
📧 联系我:mail@lxpavilion.top

浙公网安备 33010602011771号