routeAgentRequest() 是可选的。任何通过 fetch() 到达 Lifecycle Durable Object 的请求都会经过 Lifecycle,无论 Worker 如何找到该对象。如果你想使用自己的 URL,或者由服务器而非客户端决定请求发往哪个对象,请使用自定义路由。
按名称获取存根并调用 fetch():
export default {
async fetch(request, env) {
const url = new URL(request.url);
// /chat/:room goes to the ChatRoom object named :room.
const room = url.pathname.match(/^\/chat\/([^/]+)/)?.[1];
if (room) {
return env.ChatRoom.getByName(decodeURIComponent(room)).fetch(request);
}
return new Response("Not found", { status: 404 });
},
};export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
// /chat/:room goes to the ChatRoom object named :room.
const room = url.pathname.match(/^\/chat\/([^/]+)/)?.[1];
if (room) {
return env.ChatRoom.getByName(decodeURIComponent(room)).fetch(request);
}
return new Response("Not found", { status: 404 });
},
} satisfies ExportedHandler<Env>;若对象处于冷状态,转发的请求会先启动对象,然后交给其能力和 onRequest() 处理。WebSocket 升级请求的处理方式相同,因此 WebSockets 能力会接受这些请求。
设置位置时,请像 routeAgentRequest() 一样寻址对象:
const namespace = env.ChatRoom.jurisdiction("eu");
const stub = namespace.get(namespace.idFromName("general"), {
locationHint: "weur",
});
const response = await stub.fetch(request);const namespace = env.ChatRoom.jurisdiction("eu");
const stub = namespace.get(namespace.idFromName("general"), {
locationHint: "weur",
});
const response = await stub.fetch(request);props 路由选项仅适用于 routeAgentRequest()。对于转发请求,请在请求中发送这些值,或通过 RPC 调用对象。
如果对象取决于调用者,请从会话中选择对象名称。客户端连接到固定路径,既看不到也不会发送名称:
import { routeAgentRequest } from "agents/routing";
async function getUserId(request) {
// Read the user from your session cookie or token.
return request.headers.get("x-user-id");
}
export default {
async fetch(request, env) {
const url = new URL(request.url);
if (url.pathname === "/me") {
const userId = await getUserId(request);
if (!userId) return new Response("Unauthorized", { status: 401 });
return env.UserAgent.getByName(userId).fetch(request);
}
return (
(await routeAgentRequest(request, env)) ??
new Response("Not found", { status: 404 })
);
},
};import { routeAgentRequest } from "agents/routing";
async function getUserId(request: Request): Promise<string | null> {
// Read the user from your session cookie or token.
return request.headers.get("x-user-id");
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
if (url.pathname === "/me") {
const userId = await getUserId(request);
if (!userId) return new Response("Unauthorized", { status: 401 });
return env.UserAgent.getByName(userId).fetch(request);
}
return (
(await routeAgentRequest(request, env)) ??
new Response("Not found", { status: 404 })
);
},
} satisfies ExportedHandler<Env>;使用 basePath 将客户端连接到该路径。agent 选项仍为必填项,但不会用于构建 URL:
import { useAgent } from "agents/react";
export function Profile() {
const agent = useAgent({
agent: "UserAgent",
basePath: "me",
onIdentity: (name, agentType) => {
console.log(`Connected to ${agentType} ${name}`);
},
});
return <p>{agent.identified ? agent.name : "Connecting..."}</p>;
}WebSockets 能力会在客户端连接时发送身份帧,因此 agent.name 和 onIdentity 会报告服务器选择的名称。如果客户端重新连接时身份发生变化(例如用户以其他身份登录),则会运行 onIdentityChange。
身份帧包含对象名称。如果名称属于私密信息(例如内部用户 ID),请勿发送。请在 WebSockets 上设置 protocol: false,并在 onConnect 中发送自己的帧。更多信息,请参阅按连接控制协议。
Durable Object 上的公共方法是 RPC 方法。你可以在 Worker 中或另一个 Durable Object 中,通过存根调用这些方法:
import { DurableObject } from "cloudflare:workers";
import { Lifecycle } from "agents/lifecycle";
import { Scheduler } from "agents/schedules";
export class UserAgent extends DurableObject {
scheduler = new Scheduler({ callbacks: {} });
lifecycle = Lifecycle.install(this).use(this.scheduler);
async pendingReminders(props) {
await this.lifecycle.start(props);
return (await this.scheduler.list()).length;
}
}
export default {
async fetch(request, env) {
const agents = env.UserAgent;
const count = await agents
.getByName("alice")
.pendingReminders({ userId: "alice" });
return Response.json({ count });
},
};import { DurableObject } from "cloudflare:workers";
import { Lifecycle } from "agents/lifecycle";
import { Scheduler } from "agents/schedules";
type Props = { userId: string };
export class UserAgent extends DurableObject<Env> {
readonly scheduler = new Scheduler({ callbacks: {} });
readonly lifecycle = Lifecycle.install<Env, Props>(this).use(this.scheduler);
async pendingReminders(props?: Props): Promise<number> {
await this.lifecycle.start(props);
return (await this.scheduler.list()).length;
}
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const agents = env.UserAgent as DurableObjectNamespace<UserAgent>;
const count = await agents
.getByName("alice")
.pendingReminders({ userId: "alice" });
return Response.json({ count });
},
} satisfies ExportedHandler<Env>;RPC 调用不会经过 fetch(),因此不会启动生命周期。在每个使用 capability 或使用 onStart() 所设置内容的 RPC 方法开头,调用 await this.lifecycle.start()。
只有在此次调用启动对象时,你传给 start() 的 props 才会生效。更多信息,请参阅启动 Lifecycle。
agents 中的 getAgentByName() 会为你启动对象,但仅适用于 Agent 类。对于普通 Durable Object,请使用 getByName() 和 lifecycle.start()。