
当防火墙封掉 WebSocket 时,实时转写会怎样
企业网络最爱放行 HTTPS,却悄悄掐断 WebSocket 升级。这会无声无息地弄坏实时转写。GeekBye v2.0.8 会自动回退到一条纯 HTTPS 传输 — 而在把它做出来的过程中,我们挖到了一个会让整个功能形同虚设的 bug。
实时转写在企业网络里失败,有一种特定的、令人抓狂的方式。你的 Wi-Fi 好好的。HTTPS 也能用 — 任何网站都打得开。可实时转写就是……不启动,而且什么都不告诉你为什么。
罪魁是这样一类企业代理:它放行普通的 HTTPS 流量,却封掉 WebSocket 升级 — 也就是把一条 HTTPS 连接变成实时转写所需的那种持久、双向通道的握手。在代理眼里,一个 WebSocket 看起来像是一条不受监控、通向网络之外的隧道,于是它把它掐了。在你眼里,转写就这么无声地坏了。
GeekBye v2.0.8 为的正是这种情况加了一个自动回退 — 而把它做出来的过程,翻出了一个会让整个功能什么都不干的 bug。
为什么是回退,而不只是重试
不稳定的网络我们早就处理了。如果你的连接在会话中途掉了,GeekBye 会带退避地重连,并缓冲你的音频,让什么都不丢 — 那是另一个功能,在为什么你的 AI 笔记助手会在糟糕的 Wi-Fi 上停下里讲过。
但被封的 WebSocket 不是一条不稳定的连接。对着一个拒绝 WebSocket 的代理去重试同一个 WebSocket,每一次都以同样的方式失败,永远如此。唯一的解法是换一种传输 — 一种看起来就像代理本来就放行的那种普通 HTTPS 的传输。
于是 v2.0.8 在同一个已认证的端点上回退到一条纯 HTTPS 传输:
- 下行(转写结果回到你这里):server-sent events —— 一条长寿命的 HTTPS 响应,代理看起来就是一次普通的流式下载。
- 上行(你的音频发出去):批量 POST 请求,每一个都带着一块音频和一个序号,这样即便网络打乱了顺序,服务器也能按序重新拼装。
没有持久套接字,没有任何看起来像隧道的东西 —— 就只是 HTTPS 的请求和响应。只要代理允许你用一个网站,它就允许这个。
那个差点把死功能发出去的 bug
这才是值得一读的部分。回退本应在 WebSocket 连接带着"传输被封"签名耗尽了它的尝试次数时触发 —— 每一次尝试都在升级这一步失败,没有认证或配额问题,至少有一次是代理形态的拒绝。一个封 WebSocket 的代理,通常会用一个 HTTP 403 Forbidden 或 407 来回应升级。
问题在于:我们的连接代码里早就有一条规则,403 意味着致命的认证错误 —— 停下,把它抛给用户,别重试。这几乎在任何地方都对。但它意味着,来自封锁型代理的那个 403 —— 那个本该触发回退的确切信号 —— 反而在回退逻辑有机会跑起来之前就被当成致命错误抛了出去。只有一次裸的连接掉线(一次 1006 关闭)才落到了回退里。于是这个功能本会在那个罕见情形下工作,却对它真正的主要目标 —— 企业代理 —— 无声地失败。
我们是在给这次发布做加固时抓到它的,不是在生产里。修复:WebSocket 升级 那一段上的 403/407 现在被当作可恢复,好让连接循环能耗尽并落进回退 —— 而一次真正的认证失败(它以不同的方式抵达,是在升级成功之后)仍然快速失败,和以前一模一样。一个回归测试现在把这个区别钉死了:一个封锁型代理的 403 必须回退;一个真的认证 403 绝不能回退。
其余的加固沿着同一条多疑的思路:给每一个上行 POST 都加超时,好让一个接了请求却永不作答的代理没法把音频流卡住;并保证一个真正的登录问题绝不会被回退这套机器悄悄掩盖掉。
我们对着一个真正有敌意的代理做了测试
一个存在意义完全在于活过有敌意的网络的功能,没法只靠单元测试来验证 —— 单元测试里没有代理。在启用它之前,我们让真正的应用穿过一个本地反向代理,而它被配置成就干企业代理干的那件事:转发 HTTPS,用 403 拒绝 WebSocket 升级。
日志里留下的痕迹就是收据:四次被封的 WebSocket 尝试,被识别出的耗尽签名,自动切换到 HTTPS 传输,然后是一段在纯 HTTPS 上健康跑完的 96 秒转写会话 —— 66 个转写片段,零丢弃。故障转移能工作,是因为我们亲眼看着它转移过去了。
三条可迁移的教训
- "在不稳定的 Wi-Fi 上能用"和"在有敌意的代理后面能用"是两种不同的保证。 一个需要重连,另一个需要换一种传输。把两者混为一谈,就会让一整群企业用户在无声中坏掉。
- 你的错误分类,可能把你自己的功能对它自己藏起来。 一条 99% 的时候都对的规则(403 = 致命认证)对这个功能存在的意义所在的那 1% 恰恰是错的。当你加一个回退时,审一审那个触发条件到底能不能走到回退。
- 测那个对手,别只测顺风路径。 "活过一个封 WebSocket 的代理"唯一诚实的测法,就是一个封 WebSocket 的代理。我们造了一个。
GeekBye v2.0.8 发布了这条 HTTPS 回退,带标志位开关且经过验证。与它并肩的可靠性工作,见为什么你的 AI 笔记助手会在糟糕的 Wi-Fi 上停下;这一系列里相邻的发布,见为什么你的 AI 笔记助手会在会议中途停止录音(v2.0.9)以及为什么 AI 转写总是听错技术术语(v2.0.11)。