生成模型:Claude Opus 4.6 (anthropic/claude-opus-4-6) Token 消耗:输入 ~190k tokens,输出 ~5k tokens(本节)
前三节我们依次解析了浏览器控制的三个层次:架构概览、CDP 低级层、Playwright 高级层。本节将分析最外层——浏览器 HTTP 服务器,它将所有能力封装为 RESTful API,供 Gateway 和 Agent 工具层调用。
16.4.1 浏览器 HTTP 服务器
// src/browser/server.ts — startBrowserControlServerFromConfig
export async function startBrowserControlServerFromConfig() {
const cfg = loadConfig();
const resolved = resolveBrowserConfig(cfg.browser, cfg);
if (!resolved.enabled) return null;
const app = express();
app.use(express.json({ limit: "1mb" }));
// 注册路由
const ctx = createBrowserRouteContext({ getState: () => state });
registerBrowserRoutes(app, ctx);
// 绑定到 127.0.0.1(仅本地访问)
const server = await app.listen(resolved.controlPort, "127.0.0.1");
state = {
server,
port: resolved.controlPort,
resolved,
profiles: new Map(),
};
// 为 extension 模式的配置文件预启动 Relay 服务器
for (const name of Object.keys(resolved.profiles)) {
const profile = resolveProfile(resolved, name);
if (profile?.driver === "extension") {
await ensureChromeExtensionRelayServer({ cdpUrl: profile.cdpUrl });
}
}
return state;
}
关键设计点:
绑定到 127.0.0.1——浏览器控制服务仅本地可访问,不暴露到网络
profiles Map——每个配置文件的运行时状态(浏览器进程、最后活跃标签页等)
Extension Relay 预启动——如果配置文件使用 Chrome 扩展模式,在服务器启动时就启动 Relay,不等第一次操作
16.4.2 服务器上下文与标签页管理
createBrowserRouteContext() 为每个路由请求创建配置文件作用域的操作上下文:
lastTargetId 的设计目的:当 Agent 不指定 targetId 时,默认使用最后操作的标签页。这符合人类的浏览习惯——"继续在当前标签页操作"。
标签页的打开支持两种方式:
标签页关闭类似——本地通过 CDP /json/close/${targetId},远程通过 Playwright。
client-actions.ts 是四个子模块的聚合:
客户端动作层位于浏览器服务器路由和 Playwright 工具核心之间——它将 HTTP 请求参数转换为 Playwright 函数调用,并格式化响应。
16.4.4 Chrome 扩展中继
在 extension 驱动模式下,用户的 Chrome 不是由 OpenClaw 启动的——它没有 --remote-debugging-port 参数,无法直接通过 CDP 连接。Chrome Extension Relay 解决这个问题:
衍生解释:Chrome 扩展(Extension)运行在浏览器内部,拥有比普通网页更高的权限——可以访问 chrome.debugger API,这个 API 提供了与 CDP 等价的功能。OpenClaw 的中继架构利用这一点:扩展在浏览器内部执行 CDP 命令,然后通过 WebSocket 将结果转发给 OpenClaw 的 Relay Server。
通信流程:
OpenClaw 通过本地 Relay Server 连接到扩展的 WebSocket
发送 forwardCDPCommand 消息(包含 CDP 方法和参数)
扩展在浏览器内执行 chrome.debugger.sendCommand()
扩展将结果通过 ExtensionResponseMessage 返回
浏览器事件(如页面加载完成)通过 forwardCDPEvent 推送
Relay Server 在启动时生成随机 token,存储在配置中。扩展连接时需要提供此 token。这防止其他程序冒充扩展连接到 Relay Server。
Relay 内部维护了一个**已连接目标(Connected Target)**表:
当扩展检测到 Target.attachedToTarget 事件时,将新目标加入表中;检测到 Target.detachedFromTarget 时移除。这样 OpenClaw 知道哪些标签页是可以操作的。
16.4.5 Bridge Server
bridge-server.ts 提供了一个额外的 HTTP 服务,充当 Agent 工具层和浏览器控制服务之间的桥梁。它在 Agent 运行的上下文中启动(可能在 Docker 容器内),将请求转发到宿主机上的浏览器控制服务。
这在沙箱模式下特别重要:
浏览器 HTTP 服务器绑定到 127.0.0.1(仅本地),通过 Express 提供 RESTful API
配置文件上下文为每个浏览器实例提供隔离的操作接口——标签页列表、打开/关闭、启停浏览器
lastTargetId 记录最后操作的标签页,Agent 不指定时默认使用,符合人类浏览习惯
客户端动作层是路由和 Playwright 之间的适配器——核心/观察/状态三类动作覆盖所有浏览器操作
Chrome 扩展中继解决了"用户已有 Chrome"的问题——扩展在浏览器内执行 CDP 命令,通过 WebSocket 转发给 OpenClaw
Bridge Server 在沙箱模式下作为 Docker 容器和宿主机之间的转发器
整个服务器栈:Agent Tool → Bridge (沙箱) → Browser Control Server → CDP/Playwright → Chrome