网关控制平面:连接、鉴权、分发、广播

网关控制平面:连接、鉴权、分发、广播

这一章关注“入口层”的确定性:请求怎么进来、怎么被允许、怎么被路由、怎么把结果与事件发回去。

适用范围

  • 你要实现一个“控制面网关”(WS/HTTP)来承载 UI、CLI、渠道接入与运维接口
  • 你要能解释为什么必须“先握手再业务”、为什么事件不能无差别广播

最小可验证闭环(先跑通再看细节)

  1. 启动 Gateway:
openclaw gateway
  1. 打开 Control UI:
openclaw dashboard
  1. 观察握手与事件流(tick/presence/...):

执行链路(从“第一包”到“事件广播”)

  1. 握手:第一包必须是 connect(含 challenge/鉴权)。
  2. 鉴权:按 role + scopes 决定能否调用某个 method。
  3. 分发:把 req(method, params) 路由到 handler。
  4. 广播:把执行过程中的状态/输出作为 event 推送给订阅者(并做事件级过滤与慢连接保护)。

具体协议形态与方法表见:

关键实现要点(按复刻顺序)

1) connect 必须是首包

  • 未完成握手的连接,不应允许进入业务 method handler。
  • 握手成功后再允许订阅事件、调用方法。

2) authorize 与 dispatch 解耦

建议把逻辑拆成两步:

  1. authorize(method, role, scopes):决定“能不能调”
  2. dispatch(method, params):决定“交给谁处理”

这样能把权限策略与业务处理解耦,并让审计与排障更清晰。

3) handler 的优先级:插件/扩展点优先,再 core 兜底

当存在扩展点(例如插件注册的 gateway method)时,建议:

  • 先尝试 extra/plugin handlers
  • 再落到 core handlers
  • 未命中返回明确的 unknown method(不要静默)

相关治理见:Hook 与插件治理

4) 事件广播必须做 scope guard + 慢连接保护

  • 不是所有事件都能对所有连接广播(尤其是审批、配对、敏感运维类事件)。
  • 需要对慢消费者做保护:单连接写缓冲持续积压时,应降级/断开,避免拖垮整体。

最小帧形态(便于你在抓包/日志里对照)

请求:

{ "type": "req", "id": "1", "method": "chat.send", "params": { "text": "hi" } }

响应(ACK,返回 runId):

{ "type": "res", "id": "1", "ok": true, "result": { "runId": "r_123" } }

事件(流式输出/状态变更):

{ "type": "event", "event": "agent.delta", "payload": { "runId": "r_123", "delta": "..." } }

你实现时最容易踩坑的点

  • 没有把 connect 作为首包约束:导致未认证请求也能进入业务 handler。
  • 把广播做成“全量广播”:敏感事件(审批、配对等)必须按 scope 过滤。
  • 缺少慢消费者保护:单个连接的写缓冲积压会拖垮整个网关进程。

排障入口(从症状快速定位)

  • WS 连不上/握手失败:先读 Gateway 协议 的 connect/challenge,再看 健康检查
  • unknown method:确认 method 名是否正确、插件是否启用(见 CLI:plugins)。
  • 能调用但收不到事件:确认是否已订阅、事件是否受 scope 保护(见 认证与权限)。

读源码入口(可选)

这些入口用于你在源码里快速定位控制平面骨架(建议用 rg 搜文件名/方法名):

  • src/gateway/server.impl.ts
  • src/gateway/server-runtime-state.ts
  • src/gateway/server-ws-runtime.ts
  • src/gateway/server/ws-connection/message-handler.ts
  • src/gateway/server-methods.ts
  • src/gateway/server-broadcast.ts