Fiddler抓WebSocket全攻略:从握手到帧解析的配置与排查
1. 为什么WebSocket抓包和普通HTTP完全不是一回事很多人第一次用Fiddler抓WebSocket的时候都会懵明明HTTP请求抓得好好的怎么一切换到WebSocket要么看不到帧内容要么连连接都建立不起来。这不是Fiddler不好用而是WebSocket这套协议从握手到数据传输跟传统HTTP走的根本是两条路。先把底层逻辑说清楚。WebSocket在建立连接之前确实会先发一个HTTP请求做握手这个握手请求里带了Upgrade: websocket和Connection: Upgrade两个头服务端如果同意升级就返回101 Switching Protocols。从这一刻开始这条TCP连接就不再是HTTP了后续所有数据都以帧frame的形式双向流动。Fiddler默认是按HTTP代理的方式工作的它能看见握手那一下但握手之后的帧数据如果不做额外配置它要么直接透传不管要么根本解不出来。这就是为什么你抓一个普通接口Fiddler里清清楚楚换成WebSocket列表里可能只有一条101的记录点进去啥也没有。问题不在工具在于你有没有告诉Fiddler这条连接升级之后的数据我也要管。还有一个容易被忽略的点WebSocket分ws://和wss://后者是加密的。wss的握手和后续帧都跑在TLS之上Fiddler要解密就必须做中间人证书替换也就是常说的HTTPS解密。如果HTTPS解密没开wss的握手你都看不全更别说帧了。所以抓WebSocket这件事本质上是三件事的叠加HTTPS解密要开对、WebSocket协议识别要打开、帧数据的展示和过滤要配好。缺一个环节你看到的东西就是残缺的。这篇文章面向的是已经会用Fiddler抓普通HTTP、但一碰到WebSocket就卡住的开发和测试同学。我会从握手原理讲到具体配置项再讲到实际抓包时帧列表怎么读、二进制帧怎么处理、常见的抓不到和抓到是乱码怎么排查。全程按我实际调试时的顺序来你照着做基本能复现。提示本文所有操作基于Fiddler ClassicWindows桌面版。Fiddler Everywhere是另一套产品配置路径不同别混着看。2. 动手之前必须搞定的三个前置条件在打开Fiddler之前有三件事必须先确认否则后面怎么配都是白费。我把它们放在最前面是因为我见过太多人跳过这步然后在帧列表里对着空白发呆。2.1 HTTPS解密必须真正生效而不是看起来开了Fiddler抓wss的前提是它能解密TLS。操作路径是Tools Options HTTPS勾选Capture HTTPS CONNECTs和Decrypt HTTPS traffic。但勾上不等于生效关键在证书有没有被系统信任。第一次开启时Fiddler会提示安装根证书一定要点同意装到受信任的根证书颁发机构。装完之后你可以打开系统自带的证书管理器在受信任的根证书颁发机构 证书里找一下有没有Fiddler的根证书。如果只是装到了个人或者中间证书颁发机构浏览器和很多客户端是不认的握手会直接失败表现为连接被重置或者报证书错误。这里有个实操细节如果你抓的是自己开发的客户端程序比如用某个网络库写的App它可能不走系统证书库而是自带一套CA。这种情况下你得把Fiddler的根证书导出成.cer再想办法让客户端信任它否则wss永远抓不到。浏览器相对省心因为它默认信任系统库。2.2 确认WebSocket不是走的长连接轮询伪装有些项目嘴上说用WebSocket实际是HTTP long polling或者SSE。这两种在Fiddler里表现完全不同长轮询就是一堆普通HTTP请求SSE是一条一直不结束的HTTP响应。如果你按WebSocket的思路去配会发现根本没有101记录那说明对方压根没用WebSocket。判断方法很简单在Fiddler的会话列表里找状态码101。有101才是真WebSocket。没有的话先回去确认协议类型别在配置上死磕。2.3 代理链路要干净别让流量绕过了FiddlerFiddler本质是个本地代理默认监听127.0.0.1:8888。如果目标程序配置了自己的代理或者用了系统代理但Fiddler没设成系统代理流量就可能绕过Fiddler。检查Tools Options Connections里Act as system proxy on startup是否勾选端口是不是8888。另外如果目标服务在本机localhost或127.0.0.1有些客户端会默认不走代理导致Fiddler抓不到。这种情况要么把地址换成机器名要么在客户端里显式指定代理。这个坑我在调试本地服务时踩过不止一次。前置条件检查位置不满足的典型表现HTTPS解密生效Options HTTPS 系统证书库wss握手失败、连接重置确认是真WebSocket会话列表找101状态码只有普通HTTP请求无101代理链路正确Options Connections会话列表里完全没有目标流量这三条都过了再往下走配置才有意义。3. Fiddler里让WebSocket帧现形的关键配置前置条件满足后接下来是让Fiddler真正把WebSocket帧展示出来。默认情况下即使握手成功Fiddler对升级后的连接处理方式也可能让你看不到帧。核心配置集中在两个地方。3.1 打开WebSocket协议识别开关在Tools Options HTTPS页面往下看有一个和WebSocket相关的选项区域。不同版本措辞略有差异但核心是让Fiddler识别并处理Upgrade请求。确保与WebSocket相关的勾选项处于开启状态这样Fiddler在遇到101响应后会继续接管这条连接并解析后续帧。如果这个开关没开你会看到101记录但点进去只有握手请求和响应头帧数据是空的。这是最典型的抓到了但没内容。3.2 用FiddlerScript在握手后接管连接有些场景下光靠界面开关还不够尤其是当连接升级后Fiddler默认放行、不解析帧的时候。这时候要用FiddlerScript手动干预。路径是Rules Customize Rules打开CustomRules.js。在OnBeforeResponse或者专门处理WebSocket的回调里可以判断响应状态码是否为101如果是就标记这条会话需要继续解析。下面是一段常见的处理逻辑示意static function OnBeforeResponse(oSession: Session) { if (oSession.oResponse.headers.ExistsAndContains(Upgrade, websocket) || oSession.responseCode 101) { // 标记该会话为WebSocket让Fiddler继续解析帧 oSession[ui-color] purple; oSession[x-ProcessWebSocket] true; } }这段代码的作用是给WebSocket会话打个标记并染色方便在列表里一眼认出来。x-ProcessWebSocket这类自定义标记是否被当前版本识别取决于版本实现但染色是肯定生效的至少能帮你快速定位。改完脚本记得保存Fiddler会自动重新加载。如果没生效重启一次Fiddler。3.3 帧列表的入口在哪配置对了之后抓到的WebSocket会话在列表里通常显示为一条101记录。双击它在右侧的Inspectors面板里会多出一个WebSocket相关的标签页常见叫法是WebSocket。点进去上半部分是握手信息下半部分就是双向的帧列表。帧列表一般包含这几列方向发送/接收、帧类型文本/二进制/关闭/心跳、长度、内容预览。文本帧直接可读二进制帧需要额外处理这个后面单独讲。注意如果Inspectors里找不到WebSocket标签八成是3.1的开关没开或者当前Fiddler版本对WebSocket的支持有限。先回去确认开关再考虑升级版本。4. 读懂帧列表文本帧、二进制帧和心跳帧的处理差异帧列表出来了真正的活才刚开始。WebSocket的帧不像HTTP那样一眼能看懂不同类型的帧处理方式差别很大。这一节把常见的几类帧拆开讲。4.1 文本帧最省心但要注意分片文本帧Opcode 0x1的payload是UTF-8字符串Fiddler一般能直接显示。但WebSocket允许把一条消息拆成多个帧发送这叫分片fragmentation。第一个帧FIN0表示后面还有最后一个帧FIN1表示结束。如果Fiddler没有自动重组你会看到一条逻辑消息被拆成好几行读起来很割裂。遇到这种情况我的做法是看帧的FIN标志位手动把连续的帧拼起来。多数业务消息不会太大分片不常见但传大JSON或者文件时就会遇到。4.2 二进制帧默认是乱码得转码二进制帧Opcode 0x2的payload是原始字节Fiddler默认可能显示成乱码或者十六进制。这时候要判断业务用的是哪种序列化方式如果是Protobuf你得拿到对应的.proto文件用工具反序列化Fiddler本身解不了。如果是MessagePack同样需要对应的schema或者用通用解码器。如果是自定义二进制协议那就得对着协议文档一个字节一个字节对。实操中我常用的办法是把二进制帧的payload导出成文件再用对应的解码脚本处理。Fiddler支持右键帧导出原始数据导出后用Python脚本读import msgpack with open(frame.bin, rb) as f: data f.read() # 假设是MessagePack编码 decoded msgpack.unpackb(data, rawFalse) print(decoded)如果是Protobuf就用protoc --decode配合proto文件。这一步没有捷径协议是什么就得用什么解。4.3 心跳帧和控制帧别被它们刷屏WebSocket有几种控制帧Ping0x9、Pong0xA、Close0x8。很多长连接会定期发Ping/Pong保活频率可能几秒一次。这些帧在列表里会疯狂刷屏把真正的业务帧淹没。处理办法是在帧列表里按帧类型过滤只看文本帧和二进制帧。如果Fiddler的过滤功能不够用可以在FiddlerScript里直接跳过控制帧的展示减少噪音。帧类型Opcode是否可读处理建议文本帧0x1直接可读注意分片重组二进制帧0x2乱码按序列化方式解码Ping0x9控制帧过滤掉Pong0xA控制帧过滤掉Close0x8控制帧关注关闭原因码把这几类帧区分清楚帧列表才真正可用。否则你面对的就是一屏刷不完的Ping/Pong加乱码。5. 抓不到、抓不全、抓到乱码三类高频问题的排查链路配置和读帧都讲了但实际干活时问题往往出在抓不到上。这一节按我实际排查的顺序把三类高频问题拆开。5.1 完全抓不到WebSocket流量第一步看会话列表里有没有101。没有的话先确认代理链路回到2.3。如果连目标域名的任何请求都没有说明流量根本没进Fiddler。第二步如果有普通HTTP请求但没有101可能是HTTPS解密没生效wss握手在TLS层就失败了。回去检查证书。第三步如果101有但一闪而过可能是连接建立后立刻被关闭。看Close帧的原因码常见的是服务端鉴权失败或者协议版本不匹配。5.2 抓到了握手但帧列表是空的这是最典型的问题九成是3.1的WebSocket识别开关没开。Fiddler看到了101但没接管后续连接帧数据被直接透传了。还有一种可能是Fiddler版本较老对WebSocket的支持不完整。这种情况升级到较新版本通常能解决。升级前记得备份CustomRules.js免得自定义脚本丢失。5.3 帧内容是乱码先判断帧类型。如果是二进制帧乱码是正常的需要按4.2的方式解码。如果是文本帧却乱码可能是编码不是UTF-8或者payload被压缩了比如permessage-deflate扩展。permessage-deflate是WebSocket的一个压缩扩展握手时会协商。如果启用了帧的payload是压缩过的Fiddler可能解不出来。这种情况要么在客户端关掉这个扩展要么用支持解压的工具处理。排查时可以先看握手请求里有没有Sec-WebSocket-Extensions: permessage-deflate。提示遇到乱码先别急着怀疑工具先确认帧类型和是否压缩。这两个信息在帧列表的元数据里都能看到。6. 几个让我少走弯路的实操习惯最后分享几个我长期抓WebSocket养成的习惯都是踩坑换来的。第一先抓握手再谈帧。每次调试新连接我第一件事是看握手请求和响应头确认Upgrade、Sec-WebSocket-Key、Sec-WebSocket-Version这些字段正常。握手不对后面全是白搭。第二给WebSocket会话染色。就是3.2那段脚本干的事。列表里会话一多紫色标记能让你瞬间定位省下大量翻找时间。第三二进制协议提前准备好解码脚本。别等到抓了一堆乱码才临时找工具。项目用什么序列化提前把解码脚本写好抓到帧直接喂进去。第四过滤控制帧。Ping/Pong刷屏是常态早点过滤掉帧列表清爽很多。第五注意连接复用。有些客户端会复用同一条WebSocket连接发多种业务消息帧列表里是混在一起的。这时候要靠消息里的业务字段比如type或cmd来区分必要时在FiddlerScript里按内容高亮不同类型的消息。这套流程走下来从握手到帧、从文本到二进制、从抓不到到抓到乱码基本都覆盖了。WebSocket抓包本身不难难的是每个环节都得配对少一个环节看到的就是残缺的。把前置条件、识别开关、帧处理这三块吃透剩下的就是熟练度问题。