本教程将指导你如何使用 Cloudflare Workers 和 Turso ↗(基于 libSQL 的边缘托管分布式数据库)构建全球分布式应用。通过使用 Workers 和 Turso,你可以创建靠近终端用户的应用,而无需在数十或数百个区域维护或运营基础设施。
继续本教程之前,你应已:
- 成功创建第一个 Cloudflare Worker 和/或曾部署过 Cloudflare Worker。
- 已安装 Wrangler——用于构建 Cloudflare Workers 的命令行工具。
- 拥有 GitHub 账户 ↗,用于向 Turso 进行身份验证。
- 基本熟悉命令行界面(CLI)应用的安装和使用。
你需要 Turso CLI 来创建和填充数据库。在终端中运行以下两个命令之一来安装 Turso CLI:
# On macOS or Linux with Homebrew
brew install chiselstrike/tap/turso
# Manual scripted installation
curl -sSfL <https://get.tur.so/install.sh> | bash安装 Turso CLI 后,验证 CLI 是否在 shell 路径中:
turso --version# This should output your current Turso CLI version (your installed version may be higher):
turso version v0.51.0创建第一个 Turso 数据库之前,需要使用 GitHub 账户登录 CLI,运行:
turso auth login
Waiting for authentication...
✔ Success! Logged in as <your GitHub username>turso auth login 将打开浏览器窗口并要求你登录 GitHub 账户(若尚未登录)。首次执行此操作时,你需要授予 Turso 应用使用账户的权限。选择 Approve(批准) 以授予 Turso 所需权限。
身份验证完成后,可通过运行 turso db create <DATABASE_NAME> 创建数据库。Turso 会自动选择离你最近的位置。
turso db create my-db# Example:
[===> ]
Creating database my-db in Los Angeles, California (US) (lax)
# Once succeeded:
Created database my-db in Los Angeles, California (US) (lax) in 34 seconds.创建第一个数据库后,你现在可以直接连接并对其执行 SQL:
turso db shell my-db要开始使用数据库,创建并定义第一个表的 schema。在本示例中,你将创建 example_users 表,包含一列:email(类型为 text),然后填入一个邮箱地址。
在刚打开的 shell 中,粘贴以下 SQL:
create table example_users (email text);
insert into example_users values ('foo@bar.com');若 SQL 语句执行成功,将无输出。注意末尾的分号(;)是终止每条 SQL 语句所必需的。
输入 .quit 退出 shell。
Workers 命令行界面 Wrangler 允许你创建、本地开发和部署 Workers 项目。
要创建新的 Workers 项目(名为 worker-turso-ts),运行:
npm create cloudflare@latest -- worker-turso-tsyarn create cloudflare worker-turso-tspnpm create cloudflare@latest worker-turso-ts进行设置时,请选择以下选项:
- 对于 What would you like to start with?,选择
Hello World example。 - 对于 Which template would you like to use?,选择
Worker only。 - 对于 Which language do you want to use?,选择
TypeScript。 - 对于 Do you want to use git for version control?,选择
Yes。 - 对于 Do you want to deploy your application?,选择
No(部署前我们还会做一些修改)。
要开始开发 Worker,请 cd 进入新项目目录:
cd worker-turso-ts在项目目录中,你现在拥有以下文件:
wrangler.json/wrangler.toml:Wrangler 配置文件src/index.ts:用 TypeScript 编写的最小 Hello World Workerpackage.json:最小的 Node 依赖配置文件。tsconfig.json:包含 Workers 类型的 TypeScript 配置。仅在指定时生成。
对于本教程,只有 Wrangler 配置文件和 src/index.ts 文件相关。你无需编辑其他文件,应保持原样。
Turso 客户端库需要两项信息来建立连接:
LIBSQL_DB_URL- Turso 数据库的连接字符串。LIBSQL_DB_AUTH_TOKEN- Turso 数据库的身份验证令牌。应保密,不得提交到源代码。
要获取数据库 URL,运行以下 Turso CLI 命令并复制结果:
turso db show my-db --urllibsql://my-db-<your-github-username>.turso.io在编辑器中打开 Wrangler 配置文件,在文件底部创建新的 [vars] 部分,表示项目的环境变量:
{
"vars": {
"LIBSQL_DB_URL": "paste-your-url-here"
}
}[vars]
LIBSQL_DB_URL = "paste-your-url-here"保存对 Wrangler 配置文件的更改。
接下来,为 Worker 创建长期身份验证令牌以便连接数据库。运行以下 Turso CLI 命令,将输出复制到剪贴板:
turso db tokens create my-db -e none
# Will output a long text string (an encoded JSON Web Token)为保持此令牌保密:
- 你将创建
.dev.vars文件用于本地开发。请勿将此文件提交到源代码管理。若使用 Git,应将.dev.vars添加到.gitignore文件。
- 你还将创建密钥(secret)以保持身份验证令牌机密。
首先,创建名为 .dev.vars 的新文件,结构如下。在引号中粘贴身份验证令牌:
LIBSQL_DB_AUTH_TOKEN="<YOUR_AUTH_TOKEN>"保存对 .dev.vars 的更改。接下来,将身份验证令牌存储为生产 Worker 引用的 secret。运行以下 wrangler secret 命令,使用你的令牌创建 Secret:
# Ensure you specify the secret name exactly: your Worker will need to reference it later.
npx wrangler secret put LIBSQL_DB_AUTH_TOKEN? Enter a secret value: › <paste your token here>在键盘上按 <Enter> 保存令牌为 secret。LIBSQL_DB_URL 和 LIBSQL_DB_AUTH_TOKEN 都将在运行时可用于 Worker 的环境。
安装 Turso 客户端库和路由器:
npm i @libsql/client itty-routeryarn add @libsql/client itty-routerpnpm add @libsql/client itty-routerbun add @libsql/client itty-router@libsql/client 库允许你查询 Turso 数据库。itty-router 库是一个轻量级路由器,用于帮助处理传入 worker 的请求。
你现在将编写一个 Worker,它将:
- 处理 HTTP 请求。
- 将请求路由到特定处理程序,以列出数据库中的所有用户或添加新用户。
- 返回结果和/或成功状态。
打开 src/index.ts 并删除现有模板。完全按原样复制以下代码并粘贴到文件中:
import { Client as LibsqlClient, createClient } from "@libsql/client/web";
import { Router, RouterType } from "itty-router";
export interface Env {
// The environment variable containing your the URL for your Turso database.
LIBSQL_DB_URL?: string;
// The Secret that contains the authentication token for your Turso database.
LIBSQL_DB_AUTH_TOKEN?: string;
// These objects are created before first use, then stashed here
// for future use
router?: RouterType;
}
export default {
async fetch(request, env): Promise<Response> {
if (env.router === undefined) {
env.router = buildRouter(env);
}
return env.router.fetch(request);
},
} satisfies ExportedHandler<Env>;
function buildLibsqlClient(env: Env): LibsqlClient {
const url = env.LIBSQL_DB_URL?.trim();
if (url === undefined) {
throw new Error("LIBSQL_DB_URL env var is not defined");
}
const authToken = env.LIBSQL_DB_AUTH_TOKEN?.trim();
if (authToken === undefined) {
throw new Error("LIBSQL_DB_AUTH_TOKEN env var is not defined");
}
return createClient({ url, authToken });
}
function buildRouter(env: Env): RouterType {
const router = Router();
router.get("/users", async () => {
const client = buildLibsqlClient(env);
const rs = await client.execute("select * from example_users");
return Response.json(rs);
});
router.get("/add-user", async (request) => {
const client = buildLibsqlClient(env);
const email = request.query.email;
if (email === undefined) {
return new Response("Missing email", { status: 400 });
}
if (typeof email !== "string") {
return new Response("email must be a single string", { status: 400 });
}
if (email.length === 0) {
return new Response("email length must be > 0", { status: 400 });
}
try {
await client.execute({
sql: "insert into example_users values (?)",
args: [email],
});
} catch (e) {
console.error(e);
return new Response("database insert failed");
}
return new Response("Added");
});
router.all("*", () => new Response("Not Found.", { status: 404 }));
return router;
}保存对 src/index.ts 文件的更改。
注意:
- 在使用 Cloudflare Workers 时,libSQL 客户端库导入 '@libsql/client/web' 必须完全按所示导入。非 web 导入在 Workers 环境中无法工作。
Env接口包含你先前定义的环境变量和 secret。Env接口还缓存 libSQL 客户端对象和路由器,它们在 Worker 的第一次请求时创建。/users路由从你在 Turso shell 中创建的example_users表获取所有行。它将ResultSet对象直接序列化为 JSON 返回给调用者。/add-user路由使用查询字符串中提供的值插入新行。
环境配置完成且代码就绪后,你将在部署前本地测试 Worker。
要在本地运行 Worker 实例(完全在你的机器上),运行以下命令:
npx wrangler dev你应该能看到类似以下的输出:
Your worker has access to the following bindings:
- Vars:
- LIBSQL_DB_URL: "your-url"
⎔ Starting a local server...
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ [b] open a browser, [d] open Devtools, [l] turn off local mode, [c] clear console, [x] to exit │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Debugger listening on ws://127.0.0.1:61918/1064babd-bc9d-4bed-b171-b35dab3b7680
For help, see: https://nodejs.org/en/docs/inspector
Debugger attached.
[mf:inf] Worker reloaded! (40.25KiB)
[mf:inf] Listening on 0.0.0.0:8787
[mf:inf] - http://127.0.0.1:8787
[mf:inf] - http://192.168.1.136:8787
[mf:inf] Updated `Request.cf` object cache!localhost 地址——包含 127.0.0.1 的那个——是在你机器上本地运行的 Web 服务器。
连接它并通过在浏览器中访问 /users 路由验证 Worker 返回创建 example_users 表时插入的邮箱地址:http://127.0.0.1:8787/users ↗。
你应该看到类似以下的 JSON,包含 example_users 表中的数据:
{
"columns": ["email"],
"rows": [{ "email": "foo@bar.com" }],
"rowsAffected": 0
}测试 /add-users 路由并传递要插入的邮箱地址:http://127.0.0.1:8787/add-user?email=test@test.com ↗
你应该看到文本 "Added"。若再次加载带有 /users 路由的第一个 URL(http://127.0.0.1:8787/users ↗),将显示新添加的行。你可以重复此操作任意次数。注意,由于设计原因,应用不会阻止你添加重复的邮箱地址。
在启动 Wrangler 的 shell 中输入 q 退出 Wrangler。
验证 Worker 可以连接 Turso 数据库后,部署 Worker。运行以下 Wrangler 命令将 Worker 部署到 Cloudflare 全球网络:
npx wrangler deploy首次运行此命令时,将启动浏览器,要求你使用 Cloudflare 账户登录并授予 Wrangler 权限。
deploy 命令将输出以下内容:
Your worker has access to the following bindings:
- Vars:
- LIBSQL_DB_URL: "your-url"
...
Published worker-turso-ts (0.19 sec)
https://worker-turso-ts.<your-Workers-subdomain>.workers.dev
Current Deployment ID: f9e6b48f-5aac-40bd-8f44-8a40be2212ff你现在已部署一个可以连接 Turso 数据库、查询并插入新数据的 Worker。
要清理本教程中创建的资源:
- 若不想保留此 Worker,运行
npx wrangler delete worker-turso-ts删除已部署的 Worker。 - 你也可以通过
turso db destroy my-db删除 Turso 数据库。