修复会话切换气泡丢失并重新打包
This commit is contained in:
197
docs/WEBSOCKET-TRANSPORT-EVALUATION.md
Normal file
197
docs/WEBSOCKET-TRANSPORT-EVALUATION.md
Normal file
@@ -0,0 +1,197 @@
|
||||
# cc-web WebSocket 替换为 SSE / WebTransport 评估报告
|
||||
|
||||
日期:2026-09-14
|
||||
|
||||
## 结论
|
||||
|
||||
当前项目不适合直接把 WebSocket 整体替换成 SSE 或 WebTransport。
|
||||
|
||||
推荐保留 WebSocket 作为默认双向控制通道,同时增加“认证后的 SSE 下行通道 + HTTP
|
||||
命令接口”的渐进式方案。这样可以先降低代理对 WebSocket 的依赖,并保留现有协议和
|
||||
回退能力。WebTransport 适合后续独立 PoC,不建议作为近期生产替换目标。
|
||||
|
||||
| 方案 | 当前项目可行性 | 适合的范围 | 主要结论 |
|
||||
|---|---:|---|---|
|
||||
| 继续使用 WebSocket | 高 | 现有全部功能 | 成本最低,协议已覆盖双向消息、审批和实时输出 |
|
||||
| SSE + HTTP 命令 | 高(渐进式) | 服务端事件下行、流式输出 | 推荐;需要事件总线、重放和认证改造 |
|
||||
| 纯 SSE 替换 | 中低 | 只读监控或单向推送 | 不匹配当前大量客户端命令和交互式请求 |
|
||||
| WebTransport | 中低(近期),高(专用场景) | 高并发低延迟、可靠流+不可靠数据报 | 基础设施和 Node 服务端生态成本过高 |
|
||||
|
||||
## 当前 WebSocket 的职责
|
||||
|
||||
项目的 WebSocket 并非只用来传输模型文本,而是整个浏览器会话的双向 RPC 通道。
|
||||
|
||||
- `server.js:9330-9575` 创建 `/ws` 的 `WebSocketServer`,在首帧完成密码或 token
|
||||
认证,然后按 JSON `type` 分发命令。
|
||||
- 客户端在 `public/app.js:7781-7870` 建立连接、解析 JSON、指数退避重连,并在
|
||||
`public/app.js:7191-7204` 等位置通过同一连接发送命令。
|
||||
- 普通 Claude/Codex 运行时在 `lib/agent-runtime.js:359-590` 产生
|
||||
`text_delta`、`content_blocks`、`tool_start/update/end`、`usage` 等事件;Codex
|
||||
App 在 `lib/codex-app-runtime.js:437` 复用相同下行抽象。
|
||||
- 服务端还按会话查看关系发送事件(`server.js:6835-6851`),并向所有认证客户端
|
||||
广播任务看板和后台完成事件(`server.js:6512-6529`、`server.js:6827-6831`)。
|
||||
- `activeProcesses`、`activeCodexAppTurns` 和 `wsSessionMap`
|
||||
(`server.js:1420-1503`)把运行中的进程、当前会话和连接绑定在内存中。断线时
|
||||
`handleDisconnect`(`server.js:11397-11425`)解绑连接,但进程继续运行,重连后再
|
||||
恢复查看。
|
||||
- 客户端和服务端都有心跳:服务端 WebSocket ping 在 `server.js:9578-9604`,客户端
|
||||
应用层 heartbeat 在 `public/app.js:7720-7775`。这也是当前反向代理长连接稳定性的
|
||||
一部分。
|
||||
|
||||
因此,替换传输层必须保留以下语义:实时增量、工具调用生命周期、审批/引导输入的
|
||||
双向往返、会话切换与恢复、跨会话广播、断线重连、重复命令保护和后台任务通知。
|
||||
|
||||
## SSE 评估
|
||||
|
||||
### 可行性
|
||||
|
||||
SSE 很适合承载本项目的服务端下行事件。`text_delta`、工具状态、`done`、会话列表、
|
||||
任务看板和提示事件都可以编码为带 `event`、`id`、`data` 的 SSE 帧。浏览器原生
|
||||
`EventSource` 自带自动重连,服务端可用注释心跳保持连接。
|
||||
|
||||
但 SSE 只能由服务器向浏览器推送。当前客户端发送的 `message`、`abort`、会话管理、
|
||||
设置、任务看板查询、审批响应和引导输入响应必须迁移到 HTTP `POST`/`PATCH`/`DELETE`
|
||||
命令接口,或继续由 WebSocket 承担。这意味着“纯 SSE”不是小改动;“SSE 下行 + HTTP
|
||||
命令”才是可行的替代架构。
|
||||
|
||||
### 优点
|
||||
|
||||
- 基于普通 HTTP,Nginx、Caddy、云负载均衡和审计工具更容易接入。
|
||||
- 浏览器 API 简单,断线重连和 `Last-Event-ID` 已有标准语义。
|
||||
- 事件天然是文本 JSON,与当前 `wsSend(JSON.stringify(data))` 的消息模型接近。
|
||||
- 单向输出的代码边界清晰,适合模型流式文本、工具进度和只读监控。
|
||||
- 不需要 UDP/443、QUIC、HTTP/3 或新的服务端运行时。
|
||||
|
||||
### 缺点和改造点
|
||||
|
||||
- 不能承载现有客户端到服务端的命令;需要新建命令路由、请求 ID、错误响应和幂等控制。
|
||||
- 原生 `EventSource` 不能设置自定义 `Authorization` 头。当前 token 放在首个 WebSocket
|
||||
JSON 帧中,迁移时应优先改为安全 Cookie(配套 CSRF 防护),或使用 `fetch` 流式读取;
|
||||
把 token 放 URL 会进入代理日志、历史记录和监控标签,不建议。
|
||||
- 当前仅保存在会话 JSON 和运行态文件中的状态不足以重放每个增量。必须为 SSE 事件分配
|
||||
单调 `id`,并增加短期事件缓冲或按 `sessionId` 重发快照,否则网络抖动时会丢字、丢工具状态。
|
||||
- HTTP/1.1 下浏览器对同源并发连接数有限;HTTP/2 可改善连接复用,但反向代理必须关闭
|
||||
响应缓冲并提高读超时。Nginx 通常需要 `proxy_buffering off`、`X-Accel-Buffering: no`
|
||||
和足够大的 `proxy_read_timeout`。
|
||||
- 一条 SSE 流是有序可靠字节流;慢客户端会形成反压,需要限制队列、丢弃可重建事件或
|
||||
断开慢连接,不能无限堆积内存。
|
||||
- 水平扩展时,SSE 客户端和运行进程仍绑定单个 Node 实例;需要粘性会话或 Redis/NATS
|
||||
等发布订阅与事件重放层。当前项目没有这层基础设施。
|
||||
|
||||
### 对当前项目的评分
|
||||
|
||||
| 指标 | SSE 下行 + HTTP 命令 |
|
||||
|---|---:|
|
||||
| 代码复用 | 7/10 |
|
||||
| 浏览器兼容 | 9/10 |
|
||||
| 代理/部署 | 8/10 |
|
||||
| 双向交互适配 | 6/10 |
|
||||
| 断线恢复 | 需新增 6/10 |
|
||||
| 近期落地建议 | 推荐灰度 |
|
||||
|
||||
## WebTransport 评估
|
||||
|
||||
### 可行性
|
||||
|
||||
WebTransport 基于 HTTP/3/QUIC,同时提供可靠的双向流和可丢失的数据报,理论上可以
|
||||
较完整地承接当前 WebSocket 的双向 JSON 协议。普通命令、审批和模型文本应使用可靠
|
||||
双向流;只有明确允许丢失的高频状态才考虑数据报。
|
||||
|
||||
当前项目的 Node `http.createServer` + `ws` 结构没有现成 WebTransport 入口。引入后需要
|
||||
HTTP/3/QUIC 服务端库或独立网关、证书和连接管理;现有 `/ws` 的升级、心跳、认证、
|
||||
反向代理配置和运维监控均不能直接复用。
|
||||
|
||||
### 优点
|
||||
|
||||
- 原生双向通信,命令和事件不必拆成两套协议。
|
||||
- QUIC 在多条流之间避免 TCP 层队头阻塞;建立连接和网络切换体验可能更好。
|
||||
- 可按场景选择可靠流或低延迟数据报,适合未来高频协作光标、实时遥测等功能。
|
||||
- 连接由 HTTP/3 承载,具备现代传输层的多路复用能力。
|
||||
|
||||
### 缺点和风险
|
||||
|
||||
- 浏览器必须处于安全上下文,服务端和代理必须支持 HTTP/3/QUIC;UDP/443、防火墙、
|
||||
云负载均衡和企业网络放行都成为部署前置条件。
|
||||
- Node 核心当前没有与 `ws` 同等成熟、可直接替换的稳定高层 WebTransport 服务端 API,
|
||||
需要评估第三方库或独立网关的维护状态、内存安全和协议兼容性。
|
||||
- 现有 Nginx/HTTP 反向代理配置按 HTTP/1.1 WebSocket 编写,不能假设能透明转发
|
||||
WebTransport;需要逐个验证 HTTP/3 终止点、QUIC 到后端的转发方式和超时策略。
|
||||
- 数据报不保证送达、顺序或不重复,不能承载文本增量、审批、abort、会话切换等关键
|
||||
消息;可靠流仍需实现应用层消息边界、背压、重连和幂等。
|
||||
- 连接迁移、连接 ID、TLS、HTTP/3 日志和指标与当前 WebSocket 运维经验不同,故障排查
|
||||
成本明显更高。
|
||||
- Safari、旧版浏览器、企业代理和受限网络的可用性需要实测,生产仍需 WebSocket/SSE
|
||||
回退;这会带来三套客户端和协议测试矩阵。
|
||||
|
||||
### 对当前项目的评分
|
||||
|
||||
| 指标 | WebTransport |
|
||||
|---|---:|
|
||||
| 代码复用 | 5/10 |
|
||||
| 浏览器兼容 | 5/10(需目标用户实测) |
|
||||
| 代理/部署 | 3/10 |
|
||||
| 双向交互适配 | 8/10 |
|
||||
| 低延迟/多路复用潜力 | 9/10 |
|
||||
| 近期落地建议 | 不推荐直接替换 |
|
||||
|
||||
## 改造规模与风险
|
||||
|
||||
| 领域 | SSE 方案 | WebTransport 方案 |
|
||||
|---|---|---|
|
||||
| 服务端 | 抽象 `wsSend` 为事件发布器;新增 SSE 连接、命令 API、事件 ID/重放 | 替换连接层、增加 HTTP/3/QUIC 服务端和可靠流协议 |
|
||||
| 前端 | `EventSource`/fetch 流读取;把 `send()` 改为 HTTP 命令;保留统一消息处理器 | 新建 WebTransport 客户端、流帧协议、能力探测和多级回退 |
|
||||
| 认证 | Cookie+CSRF 或 fetch 自定义头;处理连接失效 | QUIC 握手后应用认证、连接恢复和 token 轮换 |
|
||||
| 恢复 | `Last-Event-ID`、事件缓冲、会话快照 | 连接迁移、流重建、消息幂等与快照 |
|
||||
| 部署 | 代理关闭缓冲、长超时,HTTP/2 优先 | HTTP/3、UDP/443、证书、网关、监控和防火墙 |
|
||||
| 测试 | 事件顺序、重放、慢客户端、代理超时、CSRF | 可靠/不可靠流、丢包、网络切换、浏览器和代理矩阵 |
|
||||
| 估算 | 2–4 人周做灰度骨架,4–8 人周完成替换 | 6–12 人周 PoC,生产化通常更久,取决于网关和网络 |
|
||||
|
||||
上述估算不包含新增 Redis/NATS、HTTP/3 网关或大规模压测;多实例部署会增加工作量。
|
||||
|
||||
## 推荐实施路线
|
||||
|
||||
1. 先把 `wsSend`、`sendSessionEventToViewers`、全局广播和运行时 `sendRuntime` 收敛到
|
||||
一个传输无关的事件发布接口,统一事件名、`sessionId`、`requestId`、时间戳和递增
|
||||
`eventId`。保留现有 WebSocket 适配器,确保这一步行为不变。
|
||||
2. 增加受保护的 `/api/events` SSE 端点,只接入只读会话列表、任务事件和运行时下行事件。
|
||||
对每个连接限制队列,发送注释心跳,并支持 `Last-Event-ID` 后按会话重发快照。
|
||||
3. 以 Cookie 或 `fetch` 流读取解决认证,不把长期 token 放入 URL;命令端点使用
|
||||
`requestId` 和幂等键,返回 202 后由 SSE 回传结果。先迁移 `message`、`abort`、会话
|
||||
切换和审批响应,再迁移设置与任务看板命令。
|
||||
4. 对比 WebSocket 与 SSE 的首字延迟、完整回合延迟、断线恢复丢事件数、慢客户端内存、
|
||||
代理超时和移动网络表现。通过特性开关按用户或会话灰度,WebSocket 保留为回退。
|
||||
5. 只有在所有命令均有 HTTP 等价物、事件重放和多实例路由验证通过后,才考虑下线默认
|
||||
WebSocket;机器人和内部集成需单独迁移,不能只看浏览器 UI。
|
||||
6. 如确有 QUIC 需求,再建立独立 WebTransport PoC,先验证目标浏览器、TLS/HTTP3 网关、
|
||||
UDP 网络、可靠流重连和监控,再决定是否替代 SSE/WS。
|
||||
|
||||
## 最终建议
|
||||
|
||||
对 cc-web 当前“模型流式输出 + 交互式审批 + 会话控制 + 单 Node 进程状态绑定”的
|
||||
形态,优先级应为:
|
||||
|
||||
1. **近期:继续 WebSocket,先做传输无关事件层和协议整理。**
|
||||
2. **中期:SSE 下行 + HTTP 命令灰度,逐步减少对 WebSocket 的依赖。**
|
||||
3. **长期:只有在确认 HTTP/3/QUIC 基础设施和用户浏览器覆盖后,才评估 WebTransport。**
|
||||
|
||||
直接替换为 SSE 会把双向协议问题转移到大量 HTTP 命令和恢复逻辑;直接替换为
|
||||
WebTransport 则会同时引入协议、网关、网络和运维风险。混合渐进式路线能以较小范围验证
|
||||
收益,并保留可回退路径。
|
||||
|
||||
## 本地依据与限制
|
||||
|
||||
- 依据当前工作树源码和 `home-cc-web` codebase-memory 索引(索引状态:ready,节点
|
||||
8138、边 19178)完成;未修改现有源码。
|
||||
- 评估假设仍是单 Node/PM2 实例、文件会话存储和现有反向代理形态;如果部署已经具备
|
||||
HTTP/3 网关、共享消息总线或强制 Cookie 会话,WebTransport/SSE 的成本会下降。
|
||||
- 本次只读核对发现 `ccweb` 的 PM2 进程约 21 分钟前被外部定时单元重启,重启计数为
|
||||
61,环境中带有 `TRIGGER_UNIT=ccweb-restart-final-1789391174.timer`;该重启不是本次
|
||||
评估触发的。
|
||||
|
||||
## 参考标准
|
||||
|
||||
- WHATWG Server-sent events:<https://html.spec.whatwg.org/multipage/server-sent-events.html>
|
||||
- MDN Server-sent events:<https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events>
|
||||
- RFC 9297 WebTransport:<https://www.rfc-editor.org/rfc/rfc9297.html>
|
||||
- RFC 9298 WebTransport over HTTP/3:<https://www.rfc-editor.org/rfc/rfc9298.html>
|
||||
- MDN WebTransport API:<https://developer.mozilla.org/en-US/docs/Web/API/WebTransport>
|
||||
Reference in New Issue
Block a user