跳转到内容
搜索文档

路由

最后更新 查看 MarkdownAgent 设置

本指南说明请求如何路由到 Agent、命名规则,以及组织 Agent 的模式。

路由工作原理

请求到达时,routeAgentRequest() 解析 URL 并路由到相应 Agent 实例:

https://your-worker.dev/agents/{agent-name}/{instance-name}
                               └────┬────┘   └─────┬─────┘
                               Class name     Unique instance ID
                              (kebab-case)

示例 URL:

URL Agent 类 实例
/agents/counter/user-123 Counter user-123
/agents/chat-room/lobby ChatRoom lobby
/agents/my-agent/default MyAgent default

名称解析

Agent 类名自动转换为 kebab-case 用于 URL:

类名 URL 路径
Counter /agents/counter/...
MyAgent /agents/my-agent/...
ChatRoom /agents/chat-room/...
AIAssistant /agents/ai-assistant/...

路由器同时匹配原始名与 kebab-case 版本,因此两者均可使用:

  • useAgent({ agent: "Counter" })/agents/counter/...
  • useAgent({ agent: "counter" })/agents/counter/...

使用 routeAgentRequest()

routeAgentRequest() 是 Agent 路由的主入口:

import { routeAgentRequest } from "agents";

export default {
	async fetch(request, env, ctx) {
		// Route to agents - returns Response or undefined
		const agentResponse = await routeAgentRequest(request, env);

		if (agentResponse) {
			return agentResponse;
		}

		// No agent matched - handle other routes
		return new Response("Not found", { status: 404 });
	},
};
import { routeAgentRequest } from "agents";

export default {
	async fetch(request: Request, env: Env, ctx: ExecutionContext) {
		// Route to agents - returns Response or undefined
		const agentResponse = await routeAgentRequest(request, env);

		if (agentResponse) {
			return agentResponse;
		}

		// No agent matched - handle other routes
		return new Response("Not found", { status: 404 });
	},
} satisfies ExportedHandler<Env>;

实例命名模式

实例名(URL 最后一段)决定由哪个 Agent 实例处理请求。每个唯一名称对应独立 Agent 与独立 state。

按用户 Agent

每个用户拥有独立 Agent 实例:

// Client
const agent = useAgent({
	agent: "UserProfile",
	name: `user-${userId}`, // e.g., "user-abc123"
});
// Client
const agent = useAgent({
	agent: "UserProfile",
	name: `user-${userId}`, // e.g., "user-abc123"
});
/agents/user-profile/user-abc123 → User abc123's agent
/agents/user-profile/user-xyz789 → User xyz789's agent (separate instance)

共享 room

多个用户共享同一 Agent 实例:

// Client
const agent = useAgent({
	agent: "ChatRoom",
	name: roomId, // e.g., "general" or "room-42"
});
// Client
const agent = useAgent({
	agent: "ChatRoom",
	name: roomId, // e.g., "general" or "room-42"
});
/agents/chat-room/general → All users in "general" share this agent

全局单例

整个应用的全局单例:

// Client
const agent = useAgent({
	agent: "AppConfig",
	name: "default", // Or any consistent name
});
// Client
const agent = useAgent({
	agent: "AppConfig",
	name: "default", // Or any consistent name
});

动态命名

根据上下文生成实例名:

// Per-session
const agent = useAgent({
	agent: "Session",
	name: sessionId,
});

// Per-document
const agent = useAgent({
	agent: "Document",
	name: `doc-${documentId}`,
});

// Per-game
const agent = useAgent({
	agent: "Game",
	name: `game-${gameId}-${Date.now()}`,
});
// Per-session
const agent = useAgent({
	agent: "Session",
	name: sessionId,
});

// Per-document
const agent = useAgent({
	agent: "Document",
	name: `doc-${documentId}`,
});

// Per-game
const agent = useAgent({
	agent: "Game",
	name: `game-${gameId}-${Date.now()}`,
});

自定义 URL 路由

需要控制 URL 结构的高级场景可绕过默认 /agents/{agent}/{name} 模式。

使用 basePath(客户端)

basePath 选项允许客户端连接任意 URL 路径:

// Client connects to /user instead of /agents/user-agent/...
const agent = useAgent({
	agent: "UserAgent", // Required but ignored when basePath is set
	basePath: "user", // → connects to /user
});
// Client connects to /user instead of /agents/user-agent/...
const agent = useAgent({
	agent: "UserAgent", // Required but ignored when basePath is set
	basePath: "user", // → connects to /user
});

适用于以下情况:

  • 需要无 /agents/ 前缀的简洁 URL
  • 实例名由服务端决定(例如来自 auth/session)
  • 与现有 URL 结构集成

服务端实例选择

使用 basePath 时服务端须处理路由。用 getAgentByName() 获取 Agent 实例,再用 fetch() 转发请求:

export default {
	async fetch(request, env) {
		const url = new URL(request.url);

		// Custom routing - server determines instance from session
		if (url.pathname.startsWith("/user/")) {
			const session = await getSession(request);
			const agent = await getAgentByName(env.UserAgent, session.userId);
			return agent.fetch(request); // Forward request directly to agent
		}

		// Default routing for standard /agents/... paths
		return (
			(await routeAgentRequest(request, env)) ??
			new Response("Not found", { status: 404 })
		);
	},
};
export default {
	async fetch(request: Request, env: Env) {
		const url = new URL(request.url);

		// Custom routing - server determines instance from session
		if (url.pathname.startsWith("/user/")) {
			const session = await getSession(request);
			const agent = await getAgentByName(env.UserAgent, session.userId);
			return agent.fetch(request); // Forward request directly to agent
		}

		// Default routing for standard /agents/... paths
		return (
			(await routeAgentRequest(request, env)) ??
			new Response("Not found", { status: 404 })
		);
	},
} satisfies ExportedHandler<Env>;

带动态实例的自定义路径

将不同路径路由到不同实例:

// Route /chat/{room} to ChatRoom agent
if (url.pathname.startsWith("/chat/")) {
	const roomId = url.pathname.replace("/chat/", "");
	const agent = await getAgentByName(env.ChatRoom, roomId);
	return agent.fetch(request);
}

// Route /doc/{id} to Document agent
if (url.pathname.startsWith("/doc/")) {
	const docId = url.pathname.replace("/doc/", "");
	const agent = await getAgentByName(env.Document, docId);
	return agent.fetch(request);
}
// Route /chat/{room} to ChatRoom agent
if (url.pathname.startsWith("/chat/")) {
	const roomId = url.pathname.replace("/chat/", "");
	const agent = await getAgentByName(env.ChatRoom, roomId);
	return agent.fetch(request);
}

// Route /doc/{id} to Document agent
if (url.pathname.startsWith("/doc/")) {
	const docId = url.pathname.replace("/doc/", "");
	const agent = await getAgentByName(env.Document, docId);
	return agent.fetch(request);
}

接收实例身份(客户端)

使用 basePath 时,客户端在服务端返回信息前不知连到哪个实例。Agent 在连接时自动发送 identity:

const agent = useAgent({
	agent: "UserAgent",
	basePath: "user",
	onIdentity: (name, agentType) => {
		console.log(`Connected to ${agentType} instance: ${name}`);
		// e.g., "Connected to user-agent instance: user-123"
	},
});

// Reactive state - re-renders when identity is received
return (
	<div>
		{agent.identified ? `Connected to: ${agent.name}` : "Connecting..."}
	</div>
);
const agent = useAgent({
	agent: "UserAgent",
	basePath: "user",
	onIdentity: (name, agentType) => {
		console.log(`Connected to ${agentType} instance: ${name}`);
		// e.g., "Connected to user-agent instance: user-123"
	},
});

// Reactive state - re-renders when identity is received
return (
	<div>
		{agent.identified ? `Connected to: ${agent.name}` : "Connecting..."}
	</div>
);

对于 AgentClient

const agent = new AgentClient({
	agent: "UserAgent",
	basePath: "user",
	host: "example.com",
	onIdentity: (name, agentType) => {
		// Update UI with actual instance name
		setInstanceName(name);
	},
});

// Wait for identity before proceeding
await agent.ready;
console.log(agent.name); // Now has the server-determined name
const agent = new AgentClient({
	agent: "UserAgent",
	basePath: "user",
	host: "example.com",
	onIdentity: (name, agentType) => {
		// Update UI with actual instance name
		setInstanceName(name);
	},
});

// Wait for identity before proceeding
await agent.ready;
console.log(agent.name); // Now has the server-determined name

处理重连时的身份变更

若重连时 identity 变化(例如 session 过期后以他人身份登录),可用 onIdentityChange 处理:

const agent = useAgent({
	agent: "UserAgent",
	basePath: "user",
	onIdentityChange: (oldName, newName, oldAgent, newAgent) => {
		console.log(`Session changed: ${oldName} → ${newName}`);
		// Refresh state, show notification, etc.
	},
});
const agent = useAgent({
	agent: "UserAgent",
	basePath: "user",
	onIdentityChange: (oldName, newName, oldAgent, newAgent) => {
		console.log(`Session changed: ${oldName} → ${newName}`);
		// Refresh state, show notification, etc.
	},
});

未提供 onIdentityChange 且 identity 变化时,会记录警告以帮助发现意外 session 变更。

为安全禁用身份

若实例名含敏感数据(session ID、内部用户 ID),可禁用 identity 发送:

class SecureAgent extends Agent {
	// Do not expose instance names to clients
	static options = { sendIdentityOnConnect: false };
}
class SecureAgent extends Agent {
	// Do not expose instance names to clients
	static options = { sendIdentityOnConnect: false };
}

禁用 identity 时:

  • agent.identified 保持 false
  • agent.ready 永不 resolve(改用 state 更新)
  • 永不调用 onIdentityonIdentityChange

何时使用自定义路由

场景 方式
标准 Agent 访问 默认值 /agents/{agent}/{name}
来自 auth/session 的实例 basePath + getAgentByName + fetch
简洁 URL(无 /agents/ 前缀) basePath + 自定义路由
旧版 URL 结构 basePath + 自定义路由
复杂路由逻辑 Worker 中自定义路由

路由选项

routeAgentRequest()getAgentByName() 均接受选项以自定义路由行为。

CORS

跨源请求时(前端在不同域上很常见):

const response = await routeAgentRequest(request, env, {
	cors: true, // Enable default CORS headers
});
const response = await routeAgentRequest(request, env, {
	cors: true, // Enable default CORS headers
});

或使用自定义 CORS 头:

const response = await routeAgentRequest(request, env, {
	cors: {
		"Access-Control-Allow-Origin": "https://myapp.com",
		"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
		"Access-Control-Allow-Headers": "Content-Type, Authorization",
	},
});
const response = await routeAgentRequest(request, env, {
	cors: {
		"Access-Control-Allow-Origin": "https://myapp.com",
		"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
		"Access-Control-Allow-Headers": "Content-Type, Authorization",
	},
});

位置提示(location hint)

对延迟敏感的应用,可提示 Agent 运行位置:

// With getAgentByName
const agent = await getAgentByName(env.MyAgent, "instance-name", {
	locationHint: "enam", // Eastern North America
});

// With routeAgentRequest (applies to all matched agents)
const response = await routeAgentRequest(request, env, {
	locationHint: "enam",
});
// With getAgentByName
const agent = await getAgentByName(env.MyAgent, "instance-name", {
	locationHint: "enam", // Eastern North America
});

// With routeAgentRequest (applies to all matched agents)
const response = await routeAgentRequest(request, env, {
	locationHint: "enam",
});

可用 location hint:wnamenamsamweureeurapacocafrme

管辖

满足数据驻留要求时:

// With getAgentByName
const agent = await getAgentByName(env.MyAgent, "instance-name", {
	jurisdiction: "eu", // EU jurisdiction
});

// With routeAgentRequest (applies to all matched agents)
const response = await routeAgentRequest(request, env, {
	jurisdiction: "eu",
});
// With getAgentByName
const agent = await getAgentByName(env.MyAgent, "instance-name", {
	jurisdiction: "eu", // EU jurisdiction
});

// With routeAgentRequest (applies to all matched agents)
const response = await routeAgentRequest(request, env, {
	jurisdiction: "eu",
});

Props

Agent 由运行时实例化而非直接构造,props 用于传递初始化参数:

const agent = await getAgentByName(env.MyAgent, "instance-name", {
	props: {
		userId: session.userId,
		config: { maxRetries: 3 },
	},
});
const agent = await getAgentByName(env.MyAgent, "instance-name", {
	props: {
		userId: session.userId,
		config: { maxRetries: 3 },
	},
});

props 传给 Agent 的 onStart 生命周期方法:

class MyAgent extends Agent {
	userId;
	config;

	async onStart(props) {
		this.userId = props?.userId;
		this.config = props?.config;
	}
}
class MyAgent extends Agent<Env, State> {
	private userId?: string;
	private config?: { maxRetries: number };

	async onStart(props?: { userId: string; config: { maxRetries: number } }) {
		this.userId = props?.userId;
		this.config = props?.config;
	}
}

routeAgentRequest 一起使用 props 时,相同 props 传给匹配 URL 的 Agent。适用于认证等通用上下文:

export default {
	async fetch(request, env) {
		const session = await getSession(request);
		return routeAgentRequest(request, env, {
			props: { userId: session.userId, role: session.role },
		});
	},
};
export default {
	async fetch(request, env) {
		const session = await getSession(request);
		return routeAgentRequest(request, env, {
			props: { userId: session.userId, role: session.role },
		});
	},
} satisfies ExportedHandler<Env>;

Agent 特定初始化请改用 getAgentByName,由你精确控制哪个 Agent 接收 props。

路由重试

服务端代码应对 transient Durable Object 路由失败重试时,将 routingRetrygetAgentByName() 一起使用:

const agent = await getAgentByName(env.MyAgent, "instance-name", {
	routingRetry: {
		maxAttempts: 3,
	},
});
const agent = await getAgentByName(env.MyAgent, "instance-name", {
	routingRetry: {
		maxAttempts: 3,
	},
});

此选项适用于请求转发与 RPC 路径,短暂路由失败应在向调用方返回错误前重试。

Hook(钩子)

routeAgentRequest 支持 hook,在请求到达 Agent 前拦截:

const response = await routeAgentRequest(request, env, {
	onBeforeConnect: (req, lobby) => {
		// Called before WebSocket connections
		// Return a Response to reject, Request to modify, or void to continue
	},
	onBeforeRequest: (req, lobby) => {
		// Called before HTTP requests
		// Return a Response to reject, Request to modify, or void to continue
	},
});
const response = await routeAgentRequest(request, env, {
	onBeforeConnect: (req, lobby) => {
		// Called before WebSocket connections
		// Return a Response to reject, Request to modify, or void to continue
	},
	onBeforeRequest: (req, lobby) => {
		// Called before HTTP requests
		// Return a Response to reject, Request to modify, or void to continue
	},
});

这些 hook 适用于认证与校验。详细示例见 跨域身份验证

服务端 Agent 访问

可在 Worker 代码中使用 getAgentByName() 访问 Agent 以进行 RPC 调用:

import { getAgentByName, routeAgentRequest } from "agents";

export default {
	async fetch(request, env) {
		const url = new URL(request.url);

		// API endpoint that interacts with an agent
		if (url.pathname === "/api/increment") {
			const counter = await getAgentByName(env.Counter, "global-counter");
			const newCount = await counter.increment();
			return Response.json({ count: newCount });
		}

		// Regular agent routing
		return (
			(await routeAgentRequest(request, env)) ??
			new Response("Not found", { status: 404 })
		);
	},
};
import { getAgentByName, routeAgentRequest } from "agents";

export default {
	async fetch(request: Request, env: Env) {
		const url = new URL(request.url);

		// API endpoint that interacts with an agent
		if (url.pathname === "/api/increment") {
			const counter = await getAgentByName(env.Counter, "global-counter");
			const newCount = await counter.increment();
			return Response.json({ count: newCount });
		}

		// Regular agent routing
		return (
			(await routeAgentRequest(request, env)) ??
			new Response("Not found", { status: 404 })
		);
	},
} satisfies ExportedHandler<Env>;

关于 locationHintjurisdictionprops 等选项,请参阅路由选项

子路径与 HTTP 方法

请求可在实例名后包含子路径。这些会传给 Agent 的 onRequest() handler:

/agents/api/v1/users     → agent: "api", instance: "v1", path: "/users"
/agents/api/v1/users/123 → agent: "api", instance: "v1", path: "/users/123"

在 Agent 中处理子路径:

export class API extends Agent {
	async onRequest(request) {
		const url = new URL(request.url);

		// url.pathname contains the full path including /agents/api/v1/...
		// Extract the sub-path after your agent's base path
		const path = url.pathname.replace(/^\/agents\/api\/[^/]+/, "");

		if (request.method === "GET" && path === "/users") {
			return Response.json(await this.getUsers());
		}

		if (request.method === "POST" && path === "/users") {
			const data = await request.json();
			return Response.json(await this.createUser(data));
		}

		return new Response("Not found", { status: 404 });
	}
}
export class API extends Agent {
	async onRequest(request: Request): Promise<Response> {
		const url = new URL(request.url);

		// url.pathname contains the full path including /agents/api/v1/...
		// Extract the sub-path after your agent's base path
		const path = url.pathname.replace(/^\/agents\/api\/[^/]+/, "");

		if (request.method === "GET" && path === "/users") {
			return Response.json(await this.getUsers());
		}

		if (request.method === "POST" && path === "/users") {
			const data = await request.json();
			return Response.json(await this.createUser(data));
		}

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

多个 Agent

一个项目可有多个 Agent 类。每个拥有独立 namespace:

// server.ts
export { Counter } from "./agents/counter";
export { ChatRoom } from "./agents/chat-room";
export { UserProfile } from "./agents/user-profile";

export default {
	async fetch(request, env) {
		return (
			(await routeAgentRequest(request, env)) ??
			new Response("Not found", { status: 404 })
		);
	},
};
// server.ts
export { Counter } from "./agents/counter";
export { ChatRoom } from "./agents/chat-room";
export { UserProfile } from "./agents/user-profile";

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

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

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

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

每个 Agent 通过各自路径访问:

/agents/counter/...
/agents/chat-room/...
/agents/user-profile/...

请求流程

请求在系统中的流转如下:

flowchart TD
    A["HTTP 请求<br/>或 WebSocket"] --> B["routeAgentRequest<br/>解析 URL 路径"]
    B --> C["按名称在 env 中<br/>查找 binding"]
    C --> D["按实例 ID<br/>获取/创建 DO"]
    D --> E["Agent 实例"]
    E --> F{"协议?"}
    F -->|WebSocket| G["onConnect(), onMessage"]
    F -->|HTTP| H["onRequest()"]

带身份验证的路由

在请求到达 Agent 前有多种认证方式。

使用身份验证 hook

routeAgentRequest() 提供 onBeforeConnectonBeforeRequest hook 用于认证:

import { Agent, routeAgentRequest } from "agents";

export default {
	async fetch(request, env) {
		return (
			(await routeAgentRequest(request, env, {
				// Run before WebSocket connections
				onBeforeConnect: async (request) => {
					const token = new URL(request.url).searchParams.get("token");
					if (!(await verifyToken(token, env))) {
						// Return a response to reject the connection
						return new Response("Unauthorized", { status: 401 });
					}
					// Return nothing to allow the connection
				},
				// Run before HTTP requests
				onBeforeRequest: async (request) => {
					const auth = request.headers.get("Authorization");
					if (!auth || !(await verifyAuth(auth, env))) {
						return new Response("Unauthorized", { status: 401 });
					}
				},
				// Optional: prepend a prefix to agent instance names
				prefix: "user-",
			})) ?? new Response("Not found", { status: 404 })
		);
	},
};
import { Agent, routeAgentRequest } from "agents";

export default {
	async fetch(request: Request, env: Env) {
		return (
			(await routeAgentRequest(request, env, {
				// Run before WebSocket connections
				onBeforeConnect: async (request) => {
					const token = new URL(request.url).searchParams.get("token");
					if (!(await verifyToken(token, env))) {
						// Return a response to reject the connection
						return new Response("Unauthorized", { status: 401 });
					}
					// Return nothing to allow the connection
				},
				// Run before HTTP requests
				onBeforeRequest: async (request) => {
					const auth = request.headers.get("Authorization");
					if (!auth || !(await verifyAuth(auth, env))) {
						return new Response("Unauthorized", { status: 401 });
					}
				},
				// Optional: prepend a prefix to agent instance names
				prefix: "user-",
			})) ?? new Response("Not found", { status: 404 })
		);
	},
} satisfies ExportedHandler<Env>;

手动身份验证

在调用 routeAgentRequest() 前检查认证:

export default {
	async fetch(request, env) {
		const url = new URL(request.url);

		// Protect agent routes
		if (url.pathname.startsWith("/agents/")) {
			const user = await authenticate(request, env);
			if (!user) {
				return new Response("Unauthorized", { status: 401 });
			}

			// Optionally, enforce that users can only access their own agents
			const instanceName = url.pathname.split("/")[3];
			if (instanceName !== `user-${user.id}`) {
				return new Response("Forbidden", { status: 403 });
			}
		}

		return (
			(await routeAgentRequest(request, env)) ??
			new Response("Not found", { status: 404 })
		);
	},
};
export default {
	async fetch(request: Request, env: Env) {
		const url = new URL(request.url);

		// Protect agent routes
		if (url.pathname.startsWith("/agents/")) {
			const user = await authenticate(request, env);
			if (!user) {
				return new Response("Unauthorized", { status: 401 });
			}

			// Optionally, enforce that users can only access their own agents
			const instanceName = url.pathname.split("/")[3];
			if (instanceName !== `user-${user.id}`) {
				return new Response("Forbidden", { status: 403 });
			}
		}

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

使用框架(Hono)

若使用 Hono 等框架,在调用 Agent 前于中间件中认证:

import { Agent, getAgentByName } from "agents";
import { Hono } from "hono";

const app = new Hono();

// Authentication middleware
app.use("/agents/*", async (c, next) => {
	const token = c.req.header("Authorization")?.replace("Bearer ", "");
	if (!token || !(await verifyToken(token, c.env))) {
		return c.json({ error: "Unauthorized" }, 401);
	}
	await next();
});

// Route to a specific agent
app.all("/agents/code-review/:id/*", async (c) => {
	const id = c.req.param("id");
	const agent = await getAgentByName(c.env.CodeReviewAgent, id);
	return agent.fetch(c.req.raw);
});

export default app;
import { Agent, getAgentByName } from "agents";
import { Hono } from "hono";

const app = new Hono<{ Bindings: Env }>();

// Authentication middleware
app.use("/agents/*", async (c, next) => {
	const token = c.req.header("Authorization")?.replace("Bearer ", "");
	if (!token || !(await verifyToken(token, c.env))) {
		return c.json({ error: "Unauthorized" }, 401);
	}
	await next();
});

// Route to a specific agent
app.all("/agents/code-review/:id/*", async (c) => {
	const id = c.req.param("id");
	const agent = await getAgentByName(c.env.CodeReviewAgent, id);
	return agent.fetch(c.req.raw);
});

export default app;

WebSocket 认证模式(URL 中的 token、JWT 刷新)见 跨域身份验证

故障排除

找不到 Agent namespace

错误消息会列出可用 Agent。检查:

  1. Agent 类已从入口点导出。
  2. 代码中类名与 wrangler.jsoncclass_name 一致。
  3. URL 使用正确的 kebab-case 名称。

请求返回 404

  1. 确认 URL 模式:/agents/{agent-name}/{instance-name}
  2. 确认在 404 handler 之前调用 routeAgentRequest()
  3. 确保返回(而非仅调用)routeAgentRequest() 的响应。

WebSocket 连接失败

  1. 不要修改 WebSocket 升级的 routeAgentRequest() 响应。
  2. 从不同源连接时确保启用 CORS。
  3. 在浏览器开发者工具中查看实际错误。

basePath 不生效

  1. 确保 Worker 处理自定义路径并转发到 Agent。
  2. 使用 getAgentByName() + agent.fetch(request) 转发请求。
  3. 设置 basePathagent 参数仍必填但被忽略。
  4. 确认服务端路由与客户端 basePath 一致。

API 参考

routeAgentRequest(request, env, options?)

将请求路由到相应 Agent。

参数 类型 描述
request Request 传入请求
env Env 含 Agent 绑定的环境
options.cors boolean | HeadersInit 启用 CORS 头
options.props Record<string, unknown> 传给处理请求的 Agent 的 props
options.locationHint string Agent 实例的首选位置
options.jurisdiction string Agent 实例的数据管辖
options.onBeforeConnect Function WebSocket 连接前回调
options.onBeforeRequest Function HTTP 请求前回调

返回值: Promise<Response | undefined> — 匹配则返回 Response,无 Agent 路由则 undefined。

getAgentByName(namespace, name, options?)

按名称获取 Agent 实例,用于服务端 RPC 或请求转发。

参数 类型 描述
namespace DurableObjectNamespace<T> 来自 env 的 Agent 绑定
name string 实例名
options.locationHint string 首选位置
options.jurisdiction string 数据管辖
options.props Record<string, unknown> 传给 onStart 的初始化属性
options.routingRetry object transient Durable Object 路由失败的重试配置

返回值: Promise<DurableObjectStub<T>> — 用于调用 Agent 方法或转发请求的类型化 stub。

useAgent(options) / AgentClient options

自定义路由的客户端连接选项:

选项 类型 描述
agent string Agent 类名(必填)
name string 实例名(默认:"default"
basePath string 完整 URL 路径 — 绕过 agent/name URL 构造
path string 追加到 URL 的额外路径
onIdentity (name, agent) => void 服务端发送 identity 时调用
onIdentityChange (oldName, newName, oldAgent, newAgent) => void 重连时 identity 变化时调用

返回值属性(React hook):

属性 类型 描述
name string 当前实例名(响应式)
agent string 当前 Agent 类名(响应式)
identified boolean 是否已收到 identity(响应式)
ready Promise<void> 收到 identity 时 resolve

Agent.options(服务端)

Agent 配置的静态选项:

选项 类型 默认值 描述
hibernate boolean true 不活跃时 Agent 是否应休眠
sendIdentityOnConnect boolean true 连接时是否向客户端发送 identity
hungScheduleTimeoutSeconds number 30 运行中 schedule 被视为挂起前的超时
class SecureAgent extends Agent {
	static options = { sendIdentityOnConnect: false };
}
class SecureAgent extends Agent {
	static options = { sendIdentityOnConnect: false };
}

后续步骤

客户端 SDK

使用 useAgent 与 AgentClient 从浏览器连接。

配置

在 wrangler.jsonc 中设置 Agent 绑定。

这篇文档对您有帮助吗?