本指南将引导您完成:
- 编写定义 Durable Object 的 JavaScript 类。
- 使用 Durable Objects SQL API 查询 Durable Object 的私有嵌入式 SQLite 数据库。
- 从另一个 Worker 实例化并与 Durable Object 通信。
- 部署 Durable Object 和与其通信的 Worker。
如果您想进一步了解 Durable Objects,请参阅什么是 Durable Objects?。
如果您想跳过步骤快速开始,请点击下方按钮。
这会在您的 GitHub 账户中创建仓库并将应用部署到 Cloudflare Workers。如果您熟悉 Cloudflare Workers 并希望跳过逐步指导,请使用此选项。
您可能是 Cloudflare Workers 新手,可能需要手动按步骤操作。
- 注册 Cloudflare 账户 ↗。
- 安装
Node.js↗。
Node.js 版本管理器
使用 Volta ↗ 或 nvm ↗ 等 Node 版本管理器,以避免权限问题并切换 Node.js 版本。本指南后续将介绍的 Wrangler 需要 Node 版本 16.17.0 或更高。
您将从 Worker 访问 Durable Object。Worker 应用是与 Durable Object 交互的界面。
要创建 Worker 项目,请运行:
npm create cloudflare@latest -- durable-object-starteryarn create cloudflare durable-object-starterpnpm create cloudflare@latest durable-object-starter运行 create cloudflare@latest 将安装 Wrangler(Workers CLI)。您将使用 Wrangler 测试和部署项目。
进行设置时,请选择以下选项:
- 对于 What would you like to start with?,选择
Hello World example。 - 对于 Which template would you like to use?,选择
Worker + Durable Objects。 - 对于 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(部署前我们还会做一些修改)。
这将创建新目录,其中包含用于编写代码的 src/index.js 或 src/index.ts 文件,以及 wrangler.jsonc 配置文件。
进入新目录:
cd durable-object-starter在创建和访问 Durable Object 之前,必须通过普通导出的 JavaScript 类定义其行为。
MyDurableObject 类的构造函数有两个参数。传递给类构造函数的第一个参数 ctx 包含 Durable Object 特定的状态,包括访问存储的方法。第二个参数 env 包含上传 Worker 时关联的任何绑定。
export class MyDurableObject extends DurableObject {
constructor(ctx, env) {
// Required, as we're extending the base class.
super(ctx, env);
}
}export class MyDurableObject extends DurableObject<Env> {
constructor(ctx: DurableObjectState, env: Env) {
// Required, as we're extending the base class.
super(ctx, env)
}
}from workers import DurableObject
class MyDurableObject(DurableObject):
def __init__(self, ctx, env):
super().__init__(ctx, env)Worker 使用远程过程调用与 Durable Object 通信。Durable Object 类上的公共方法暴露为 RPC 方法,供另一个 Worker 调用。
您的文件现在应如下所示:
export class MyDurableObject extends DurableObject {
constructor(ctx, env) {
// Required, as we're extending the base class.
super(ctx, env);
}
async sayHello() {
let result = this.ctx.storage.sql
.exec("SELECT 'Hello, World!' as greeting")
.one();
return result.greeting;
}
}export class MyDurableObject extends DurableObject<Env> {
constructor(ctx: DurableObjectState, env: Env) {
// Required, as we're extending the base class.
super(ctx, env)
}
async sayHello(): Promise<string> {
let result = this.ctx.storage.sql
.exec("SELECT 'Hello, World!' as greeting")
.one();
return result.greeting;
}
}from workers import DurableObject
class MyDurableObject(DurableObject):
async def say_hello(self):
result = self.ctx.storage.sql.exec(
"SELECT 'Hello, World!' as greeting"
).one()
return result.greeting在上面的代码中,您:
- 定义了 RPC 方法
sayHello(),Worker 可以调用它与 Durable Object 通信。 - 访问 Durable Object 的附加存储(仅对象可访问的私有 SQLite 数据库),使用
ctx.storage上可用的 SQL API 方法(sql.exec())。 - 使用
one()返回表示单行查询结果的对象,该方法检查查询结果是否恰好有一行。 - 从行对象结果返回
greeting列。
Worker 用于访问 Durable Objects。
要与 Durable Object 通信,Worker 的 fetch 处理器应如下所示:
export default {
async fetch(request, env, ctx) {
const stub = env.MY_DURABLE_OBJECT.getByName(new URL(request.url).pathname);
const greeting = await stub.sayHello();
return new Response(greeting);
},
};export default {
async fetch(request, env, ctx): Promise<Response> {
const stub = env.MY_DURABLE_OBJECT.getByName(new URL(request.url).pathname);
const greeting = await stub.sayHello();
return new Response(greeting);
},
} satisfies ExportedHandler<Env>;from workers import handler, Response, WorkerEntrypoint
from urllib.parse import urlparse
class Default(WorkerEntrypoint):
async def fetch(request):
url = urlparse(request.url)
stub = self.env.MY_DURABLE_OBJECT.getByName(url.path)
greeting = await stub.say_hello()
return Response(greeting)在上面的代码中,您:
- 导出了 Worker 的主要事件处理器,如用于接收 HTTP 请求的
fetch()处理器。 - 将
env传入fetch()处理器。绑定作为环境对象的属性传递,该对象作为第二个参数在调用事件处理器或类构造函数时传入。 - 基于提供的名称构造 Durable Object 实例的 stub。Stub 是用于向 Durable Object 发送消息的客户端对象。
- 通过调用 Durable Object 的 RPC 方法
sayHello()调用 Durable Object,返回Hello, World!字符串问候。 - 通过构造 HTTP Response
return new Response()向客户端返回 HTTP 响应。
请参阅从 Worker 访问 Durable Object了解更多关于与 Durable Object 通信的信息。
绑定 允许 Worker 与 Cloudflare 开发者平台上的资源交互。Worker 项目 Wrangler 配置文件 中的 Durable Object 绑定将包含绑定名称(本指南使用 MY_DURABLE_OBJECT)和类名(MyDurableObject)。
{
"durable_objects": {
"bindings": [
{
"name": "MY_DURABLE_OBJECT",
"class_name": "MyDurableObject"
}
]
}
}[[durable_objects.bindings]]
name = "MY_DURABLE_OBJECT"
class_name = "MyDurableObject"bindings 部分包含以下字段:
name- 必需。在 Worker 内使用的绑定名称。class_name- 必需。要绑定到的类名。script_name- 可选。默认为当前环境的 Worker 代码。
在 Wrangler 配置文件的 exports 字段中声明 Worker 导出的每个 Durable Object 类。Cloudflare 使用此声明在首次部署时 provisioning 类的 namespace,并在后续部署中管理其生命周期(重命名、删除、转移)。
注册具有 SQLite 存储的新 Durable Object 类的最小 exports 块如下所示:
{
"exports": {
"MyDurableObject": {
"type": "durable-object",
"storage": "sqlite"
}
}
}[exports.MyDurableObject]
type = "durable-object"
storage = "sqlite"请参阅 Durable Object 类导出 了解更多关于声明和管理 Durable Object 类的信息。如果您有使用旧版 migrations 数组的现有 Worker,请参阅 Durable Object 类迁移(旧版)。
要在本地测试 Durable Object,请运行 wrangler dev:
npx wrangler dev在控制台中,您应看到 Durable Object 返回的 Hello world 字符串。
要部署 Durable Object Worker:
npx wrangler deploy部署后,您应能在 Cloudflare 仪表板上看到新创建的 Durable Object Worker。
Go to Workers & Pages ↗在 <YOUR_WORKER>.<YOUR_SUBDOMAIN>.workers.dev 预览 Durable Object Worker。
您的最终代码应如下所示:
import { DurableObject } from "cloudflare:workers";
export class MyDurableObject extends DurableObject {
constructor(ctx, env) {
// Required, as we are extending the base class.
super(ctx, env);
}
async sayHello() {
let result = this.ctx.storage.sql
.exec("SELECT 'Hello, World!' as greeting")
.one();
return result.greeting;
}
}
export default {
async fetch(request, env, ctx) {
const stub = env.MY_DURABLE_OBJECT.getByName(new URL(request.url).pathname);
const greeting = await stub.sayHello();
return new Response(greeting);
},
};import { DurableObject } from "cloudflare:workers";
export class MyDurableObject extends DurableObject<Env> {
constructor(ctx: DurableObjectState, env: Env) {
// Required, as we are extending the base class.
super(ctx, env)
}
async sayHello():Promise<string> {
let result = this.ctx.storage.sql
.exec("SELECT 'Hello, World!' as greeting")
.one();
return result.greeting;
}
}
export default {
async fetch(request, env, ctx): Promise<Response> {
const stub = env.MY_DURABLE_OBJECT.getByName(new URL(request.url).pathname);
const greeting = await stub.sayHello();
return new Response(greeting);
},
} satisfies ExportedHandler<Env>;from workers import DurableObject, handler, Response
from urllib.parse import urlparse
class MyDurableObject(DurableObject):
async def say_hello(self):
result = self.ctx.storage.sql.exec(
"SELECT 'Hello, World!' as greeting"
).one()
return result.greeting
class Default(WorkerEntrypoint):
async def fetch(self, request):
url = urlparse(request.url)
stub = self.env.MY_DURABLE_OBJECT.getByName(url.path)
greeting = await stub.say_hello()
return Response(greeting)完成本教程后,您已:
- 成功创建了 Durable Object
- 通过调用 RPC 方法 调用了 Durable Object
- 全球部署了 Durable Object
- 创建 Durable Object stub
- 访问 Durable Objects 存储
- Miniflare ↗ - 用于模拟和测试 Durable Objects 的有用工具。