跳转到内容
搜索文档

快速入门

最后更新 查看 MarkdownAgent 设置

本指南将引导您完成:

  • 编写定义 Durable Object 的 JavaScript 类。
  • 使用 Durable Objects SQL API 查询 Durable Object 的私有嵌入式 SQLite 数据库。
  • 从另一个 Worker 实例化并与 Durable Object 通信。
  • 部署 Durable Object 和与其通信的 Worker。

如果您想进一步了解 Durable Objects,请参阅什么是 Durable Objects?

快速开始

如果您想跳过步骤快速开始,请点击下方按钮。

Deploy to Cloudflare

这会在您的 GitHub 账户中创建仓库并将应用部署到 Cloudflare Workers。如果您熟悉 Cloudflare Workers 并希望跳过逐步指导,请使用此选项。

您可能是 Cloudflare Workers 新手,可能需要手动按步骤操作。

前提条件

  1. 注册 Cloudflare 账户
  2. 安装 Node.js

Node.js 版本管理器

使用 Voltanvm 等 Node 版本管理器,以避免权限问题并切换 Node.js 版本。本指南后续将介绍的 Wrangler 需要 Node 版本 16.17.0 或更高。

1. 创建 Worker 项目

您将从 Worker 访问 Durable Object。Worker 应用是与 Durable Object 交互的界面。

要创建 Worker 项目,请运行:

npm 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.jssrc/index.ts 文件,以及 wrangler.jsonc 配置文件。

进入新目录:

cd durable-object-starter

2. 使用 SQL API 编写 Durable Object 类

在创建和访问 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

在上面的代码中,您:

  1. 定义了 RPC 方法 sayHello(),Worker 可以调用它与 Durable Object 通信。
  2. 访问 Durable Object 的附加存储(仅对象可访问的私有 SQLite 数据库),使用 ctx.storage 上可用的 SQL API 方法(sql.exec())。
  3. 使用 one() 返回表示单行查询结果的对象,该方法检查查询结果是否恰好有一行。
  4. 从行对象结果返回 greeting 列。

3. 实例化并与 Durable Object 通信

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)

在上面的代码中,您:

  1. 导出了 Worker 的主要事件处理器,如用于接收 HTTP 请求的 fetch() 处理器。
  2. env 传入 fetch() 处理器。绑定作为环境对象的属性传递,该对象作为第二个参数在调用事件处理器或类构造函数时传入。
  3. 基于提供的名称构造 Durable Object 实例的 stub。Stub 是用于向 Durable Object 发送消息的客户端对象。
  4. 通过调用 Durable Object 的 RPC 方法 sayHello() 调用 Durable Object,返回 Hello, World! 字符串问候。
  5. 通过构造 HTTP Response return new Response() 向客户端返回 HTTP 响应。

请参阅从 Worker 访问 Durable Object了解更多关于与 Durable Object 通信的信息。

4. 配置 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 代码。

5. 使用 SQLite 存储后端配置 Durable Object 类

在 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 类迁移(旧版)

6. 在本地开发 Durable Object Worker

要在本地测试 Durable Object,请运行 wrangler dev

npx wrangler dev

在控制台中,您应看到 Durable Object 返回的 Hello world 字符串。

7. 部署 Durable Object Worker

要部署 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);
	},
};
index.tsts
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

相关资源

这篇文档对您有帮助吗?