WebSocket 抓包和抓 HTTP 接口,第一眼看过去像两种东西。调一个 REST 接口,列表里一条请求配一条响应,点开就能看到参数和返回值;换成 WebSocket,请求列表里一般只有一条连接,点进去却挂着几十上百条消息,上行下行混在一起,中间还夹着几个看不懂的二进制帧。
这就是 WebSocket 调试容易卡住的地方——别按请求-响应的思路看它,它是一条长连接上的持续对话。TraceEagle 把这条连接拆成逐帧的消息视图,也能按方向对帧做替换。它和 HTTP 抓包有四个不一样的地方:一条连接串起整段会话、每帧都带方向、帧分文本和二进制、帧发生在 HTTP 升级之后。四个点挨个展开,顺带把改帧的思路理一遍。
HTTP 的查看单位是"一次请求",WebSocket 的查看单位是"一条连接"。
连接建立之后,客户端和服务端会在这条连接上不停地收发消息。你在请求列表里看到的那一条,背后可能已经跑了几百帧。所以别在列表里找"这条消息对应的响应"——没有这种东西。要看内容,得点进这条连接,进帧视图。
帧视图里一条一条列着收发记录,标了方向、类型和时间。刚连上时的握手、订阅、鉴权,中间的业务消息,断开前的 close 帧,都在里面。先别急着找规律,从头往下扫一遍吧。我第一次看的时候也愣了几秒(习惯性地去找 response,结果发现整个会话就是一条流)。
HTTP 的请求和响应天然分在两边,WebSocket 不是。同一条连接上,两个方向的消息混在一个列表里,所以方向标签不是装饰,是你判断问题的第一依据。
上行,也就是客户端发给服务器的那一侧,一般是建立连接、鉴权、订阅主题、用户操作、心跳。下行是服务器推给客户端的,一般是推送、广播、状态同步、确认回执。
消息没收到的时候,先确认它应该走哪个方向呢。如果一条"服务器推送"被写成了上行,那不管你怎么查服务端,都对不上——方向错了,后面基本白搭。其实方向本来就标在每一帧上,只是混在一起的时候容易看漏。
WebSocket 帧有几种类型,调试时最好分得清:
扫帧的时候,顺手把 ping / pong 跳过去,重点看文本和二进制。二进制帧别按 JSON 的思路硬套,先确认编码再说——不然很容易把正常的二进制内容当成乱码,对着它折腾半天啊。
WebSocket 的连接是"借"HTTP 建立的:客户端先发一个带
Upgrade: websocket 的 GET 请求,服务端回
101 Switching Protocols,这条连接当场切成 WebSocket 帧协议。RFC 6455 里写得很清楚。
这件事对抓包有两个影响。
一是 wss 必须先解密。如果是加密连接,证书没装好、连接没解开,你连升级请求都看不到明文,更别说后面的帧。代理会话、证书、解密范围这几步,和抓普通 HTTPS 是一样的。
二是规则要能命中这条连接。改帧的规则还是按域名、路径这类条件匹配,命中的连接才谈得上在内部改帧。连接都没进代理,规则写得再对也没用嘛。
在 TraceEagle 的规则面板里,从速查表选 WebSocket 帧改写,方向选好,再写替换关系。方向有三个选项:
| 方向 | 改哪一侧的帧 | 适合的场景 |
|---|---|---|
| 客户端→服务器 | 上行 | 改提交的参数、订阅的主题、上行的指令 |
| 服务器→客户端 | 下行 | 改推送内容、状态同步、错误码 |
| 双向 | 两边 | 同一个字段上行下行都会出现 |
替换关系写成
old=>new,也就是把帧里出现的
old 换成
new。规则保存即生效,不用重连。
举几个实际会用到的场景:聊天类应用里把指定的测试文案换掉、协作编辑里改一个占位符、推送消息里把某个状态码换成另一个值。这些都不用动客户端代码,改的是经过代理的那一份帧,改完立刻就能看到客户端怎么反应。
这里有两个细节值得提前知道。
第一,替换是按字面匹配的。大小写、空格、引号、转义都得对上。JSON 里的字段名带引号,你就把引号一起写进去;少一个字符都换不掉。
第二,动态变量支持
${...},但命名值
{name} 在帧改写里不生效。这一点在产品文档的排查表里专门写了一句。想用时间戳、随机值,直接写
${now}、
${randomUUID} 这类;别把 HTTP 改写里那套命名值搬过来,搬过来只会得到原样输出。
方向选错也很常见。明明要改服务端推下来的内容,规则却挂在上行,帧一点变化都没有。改之前先想清楚这条消息是谁发给谁的,比反复改规则省事得多。
让客户端再发一次消息,回到帧视图看新出来的那一帧。内容变了,说明规则命中了;没变,按这个顺序查:
还有一个容易忽略的点:帧改写挂在连接上,连接重连之后,只要规则还匹配,就继续生效。不用为每次重连单独配置。
WebSocket 抓包不只代理这一条路,顺手比一比。
浏览器 DevTools 的 Network 面板能看 WebSocket 帧,当前页面用起来最方便。局限也明显:只管这一个页面,原生 App、别的设备、命令行程序都够不着,批量改帧也不是它的活。
Wireshark 更偏底层,能解 WebSocket 帧,也能看到 TCP 层的重传、分片、拥塞。排查"帧为什么没到"这类网络问题时,它比应用层工具更有说服力。改流量不是它的目标。
Charles、Fiddler、Proxyman 这一路都在代理层,也能看 WebSocket。要改帧,就得看各自的规则或脚本能力,做法不太一样。
mitmproxy 用脚本处理 WebSocket 消息,灵活度最高,代价是要写代码。
TraceEagle 的定位是把"看"和"改"放在同一套规则里:HTTP 的改写、弱网、断点、WebSocket 帧改写,共用一套匹配和分组。手机上、原生 App 里的连接,也能落到同一个会话里看。它当然替代不了 Wireshark 的协议深度,两者管的是不同层的问题。
WebSocket 调试的难点不在帧本身,在习惯。把它当成一条持续对话,先看方向、再看类型,再往后才谈改不改。帧里的内容不对,先确认是哪一侧发的;要改,就把方向选对、把
old=>new 写准。
下次遇到"服务端明明推了、客户端就是没收到",别急着翻代码。先把那条连接点开,看看帧到底有没有出来吧。反正我是这么查的,十有八九能少走一段弯路。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70047460/viewspace-3186245/ ,如需转载,请注明出处,否则将追究法律责任。