跳转到内容
本站为社区维护的非官方中文翻译,与 Cloudflare, Inc. 无关联。本站不提供账户登录,请勿在任何非官方站点输入您的 Cloudflare 账户信息。官方文档:developers.cloudflare.com

路由

最后更新 查看 MarkdownAgent 设置

每个 Agent 都是一个命名的 Durable Object。路由负责让 Worker 中的请求到达正确对象。routeAgentRequest() 会从 URL 中读取 Durable Object 绑定和对象名称,并将请求转发给该对象。在对象内部,Lifecycle会接管请求,将其交给各项能力处理,然后调用你的 onRequest() 钩子。

routeAgentRequest(request, env)            Worker
└─ stub.fetch(request)                     picks the object from the URL
   └─ Lifecycle                            Durable Object
      ├─ startup, on a cold object
      ├─ capabilities, in registration order
      └─ host onRequest()

从 Worker 路由请求

routeAgentRequest() 适用于任何安装了 Lifecycle 的 Durable Object。可从 agents/routing 或 agents 导入:

src/index.jsjs
import { DurableObject } from "cloudflare:workers";
import { Lifecycle } from "agents/lifecycle";
import { routeAgentRequest } from "agents/routing";

export class MyAgent extends DurableObject {
	lifecycle = Lifecycle.install(this);

	onRequest(request) {
		return new Response(`Hello from ${this.lifecycle.name}`);
	}
}

export default {
	async fetch(request, env) {
		return (
			(await routeAgentRequest(request, env)) ??
			new Response("Not found", { status: 404 })
		);
	},
};
src/index.tsts
import { DurableObject } from "cloudflare:workers";
import { Lifecycle } from "agents/lifecycle";
import { routeAgentRequest } from "agents/routing";

export class MyAgent extends DurableObject<Env> {
	readonly lifecycle = Lifecycle.install(this);

	onRequest(request: Request): Response {
		return new Response(`Hello from ${this.lifecycle.name}`);
	}
}

export default {
	async fetch(request: Request, env: Env): Promise<Response> {
		return (
			(await routeAgentRequest(request, env)) ??
			new Response("Not found", { status: 404 })
		);
	},
} satisfies ExportedHandler<Env>;

将此类绑定为基于 SQLite 的 Durable Object:

{
	"durable_objects": {
		"bindings": [{ "name": "MyAgent", "class_name": "MyAgent" }],
	},
	"migrations": [{ "tag": "v1", "new_sqlite_classes": ["MyAgent"] }],
}
[[durable_objects.bindings]]
name = "MyAgent"
class_name = "MyAgent"

[[migrations]]
tag = "v1"
new_sqlite_classes = [ "MyAgent" ]

routeAgentRequest() 可处理 HTTP 请求和 WebSocket 升级请求。它会返回:

  • 如果路径不以此前缀开头,则返回 null,以便 Worker 处理其他路由。
  • 如果路径与此前缀匹配,但没有对应的 Durable Object 绑定,则返回 400 响应。
  • 其他情况下则返回对象的响应。

URL 格式

默认 URL 格式为 /agents/:binding/:name:

https://example.com/agents/my-agent/alice/settings
                           └──┬───┘ └─┬─┘└───┬──┘
                           binding  name   sub-path
  • :binding 是 env 中 Durable Object 绑定的名称,格式为 kebab-case。绑定 MyAgent 和 MY_AGENT 都会转换为 my-agent。ChatRoom 会转换为 chat-room。
  • :name 是对象名称。路由器使用 idFromName(name) 寻址对象,对象则通过 lifecycle.name 读取名称。
  • 子路径 是名称后面的所有内容。对象会收到完整 URL,因此 onRequest() 可以根据 /settings 进行路由。

如需更改 agents 路径段,请传入 prefix 选项。

使用多个 Agent 类

导出并绑定每个类。routeAgentRequest() 会根据 URL 查找绑定,因此一次调用即可路由到所有类:

src/index.jsjs
import { routeAgentRequest } from "agents/routing";

export { ChatRoom } from "./chat-room";
export { UserProfile } from "./user-profile";

export default {
	async fetch(request, env) {
		return (
			(await routeAgentRequest(request, env)) ??
			new Response("Not found", { status: 404 })
		);
	},
};
src/index.tsts
import { routeAgentRequest } from "agents/routing";

export { ChatRoom } from "./chat-room";
export { UserProfile } from "./user-profile";

export default {
	async fetch(request: Request, env: Env): Promise<Response> {
		return (
			(await routeAgentRequest(request, env)) ??
			new Response("Not found", { status: 404 })
		);
	},
} satisfies ExportedHandler<Env>;
{
	"durable_objects": {
		"bindings": [
			{ "name": "ChatRoom", "class_name": "ChatRoom" },
			{ "name": "UserProfile", "class_name": "UserProfile" },
		],
	},
	"migrations": [
		{ "tag": "v1", "new_sqlite_classes": ["ChatRoom", "UserProfile"] },
	],
}
[[durable_objects.bindings]]
name = "ChatRoom"
class_name = "ChatRoom"

[[durable_objects.bindings]]
name = "UserProfile"
class_name = "UserProfile"

[[migrations]]
tag = "v1"
new_sqlite_classes = [ "ChatRoom", "UserProfile" ]

发往 /agents/chat-room/... 的请求会到达 ChatRoom,发往 /agents/user-profile/... 的请求会到达 UserProfile。

为 Agent 命名

名称决定哪个对象处理请求。每个名称对应一个独立对象,有自己的存储、闹钟和连接。请根据数据的共享方式选择合适的名称:

模式 名称 示例 URL
每位用户一个对象 用户 ID /agents/user-profile/user-abc123
每个资源一个对象 房间或文档 ID /agents/chat-room/general
每项任务一个对象 生成的 ID /agents/report/report-2026-10-29
单例对象 固定名称 /agents/app-config/default

对象存放私密数据时,请使用客户端无法猜到的名称,并在路由请求前检查调用者身份。更多信息,请参阅身份验证。

Lifecycle 要求对象具有名称。使用 newUniqueId() 或 idFromString() 创建对象,或对象名称超过 1,024 字节时,启动会失败。

处理子路径

对象会收到完整 URL。在 onRequest() 中匹配路径末尾:

import { DurableObject } from "cloudflare:workers";
import { Lifecycle } from "agents/lifecycle";

export class UserProfile extends DurableObject {
	lifecycle = Lifecycle.install(this);

	async onRequest(request) {
		const url = new URL(request.url);

		if (request.method === "GET" && url.pathname.endsWith("/settings")) {
			return Response.json((await this.ctx.storage.get("settings")) ?? {});
		}

		if (request.method === "PUT" && url.pathname.endsWith("/settings")) {
			await this.ctx.storage.put("settings", await request.json());
			return new Response(null, { status: 204 });
		}

		return new Response("Not found", { status: 404 });
	}
}
import { DurableObject } from "cloudflare:workers";
import { Lifecycle } from "agents/lifecycle";

export class UserProfile extends DurableObject<Env> {
	readonly lifecycle = Lifecycle.install(this);

	async onRequest(request: Request): Promise<Response> {
		const url = new URL(request.url);

		if (request.method === "GET" && url.pathname.endsWith("/settings")) {
			return Response.json((await this.ctx.storage.get("settings")) ?? {});
		}

		if (request.method === "PUT" && url.pathname.endsWith("/settings")) {
			await this.ctx.storage.put("settings", await request.json());
			return new Response(null, { status: 204 });
		}

		return new Response("Not found", { status: 404 });
	}
}

后续步骤

  • 路由选项介绍 CORS、位置选择、启动 props 和重试。
  • 身份验证会在请求到达对象之前,在 Worker 中检查调用者身份。
  • 自定义路由可通过默认 URL 格式之外的方式访问对象,包括通过 RPC 访问。
  • HTTP 和 Server-Sent Events介绍如何在 onRequest() 中处理请求并流式传输响应。
  • 请求分发介绍对象内部如何处理请求。

这篇文档对您有帮助吗?