在实时通信应用的开发过程中WebSocket 协议因其全双工、低延迟的特性成为了构建聊天、推送、在线游戏等场景的首选。然而当我们需要调试这些连接查看具体收发了什么数据时传统的 HTTP 抓包方法往往会“失灵”。最近在调试一个实时语音应用时我就深刻体会到了这一点最终通过 Charles 解决了问题。今天我就把这份从踩坑到熟练的“Charles 抓包 WebSocket 全指南”分享给大家。1. 为什么 WebSocket 抓包是个“技术活”在开始配置之前我们先要明白难点在哪。这能帮助我们理解后续每一步操作的意义。长连接 vs 短连接HTTP 请求是“一问一答”后立即断开抓包工具很容易捕获到一个个独立的请求/响应包。而 WebSocket 在初次 HTTP 握手成功后会升级协议并保持一个长连接后续所有的数据交换都在这个连接通道内以“帧”的形式传输。抓包工具需要能识别并持续监听这个特定的连接。二进制帧与文本帧WebSocket 传输的数据可以是文本Text Frame也可以是二进制数据Binary Frame比如传输的可能是 Protobuf 或音频片段。传统 HTTP 抓包视图对二进制数据的展示很不友好需要工具能正确解析和显示。SSL/TLS 加密如今绝大多数 WebSocket 连接都使用wss://即 WebSocket over TLS。这意味着抓包工具必须能够解密 HTTPS 流量一样解密这些加密的 WebSocket 数据这涉及到中间人代理和证书信任。2. 工具选型Wireshark, Fiddler 还是 Charles工欲善其事必先利其器。针对 WebSocket 抓包几个主流工具各有侧重Wireshark网络协议分析神器能抓到最底层的网络包对 WebSocket 协议帧的解析非常专业。但正因如此它过于底层配置复杂尤其是解密 TLS信息量巨大对于快速调试应用层数据流来说学习成本较高。Fiddler Classic老牌的 HTTP 调试代理对 WebSocket 有较好的支持可以直观看到消息列表。但它的界面和过滤功能相对陈旧在 macOS/Linux 上需要依靠 Mono 运行有时不够稳定。Charles本文的主角。它界面现代过滤功能强大对 HTTPS/SSL 解密配置的引导非常清晰。对于 WebSocket它能够以会话列表的形式清晰展示每条消息并且支持修改重发Repeat对于日常开发调试来说在易用性和功能性上取得了很好的平衡。综合来看如果你需要深度分析网络问题Wireshark 是终极武器如果专注于应用层的 API 调试和数据查看Charles 是目前更舒适的选择。3. 核心实战配置 Charles 抓取 WebSocket接下来我们进入正题一步步配置 Charles。3.1 代理配置首先确保 Charles 正在运行。查看代理端口在 Charles 中通过顶部菜单Proxy - Proxy Settings...打开设置。通常HTTP Proxy的端口是8888。记住这个端口。配置设备代理让你需要抓包的设备手机、电脑或浏览器的网络代理设置为 Charles 所在机器的 IP 地址和上述端口8888。例如在手机 WiFi 设置中手动配置代理。3.2 SSL 证书安装与信任这是抓取wss://流量的关键步骤。Charles 作为中间人需要让你的设备信任它颁发的证书。在 Charles 中启用 SSL 代理Proxy - SSL Proxying Settings...。勾选Enable SSL Proxying。在Locations列表中添加需要解密的域名可以偷懒地添加*:*来代理所有 HTTPS 和 WSS 流量仅限调试环境。安装 Charles 根证书PC/Mac在浏览器中访问chls.pro/sslCharles 会自动弹出安装证书的提示或者下载证书文件后手动安装到“受信任的根证书颁发机构”。iOS同样访问chls.pro/ssl根据提示安装描述文件并在设置-通用-关于本机-证书信任设置中对 Charles 证书启用完全信任。Android访问chls.pro/ssl下载证书然后在系统设置中安装。不同品牌手机路径略有差异通常位于设置-安全-加密与凭据-安装证书。多平台差异核心点iOS 和 Android 高版本对证书信任要求极为严格必须在系统级完全信任仅安装是不够的否则连接会失败。3.3 抓取与过滤 WebSocket 消息完成上述步骤后你的设备流量应该已经出现在 Charles 的Structure或Sequence视图里。识别 WebSocket 连接当你建立 WebSocket 连接时会先看到一个普通的 HTTPS 请求方法为GET状态码为101 Switching Protocols。这个就是握手请求。查看 WebSocket 消息握手成功后Charles 会将该连接识别为 WebSocket。你可以在左侧结构树中找到以ws://或wss://开头的独立条目。点击它右侧会切换到WebSocket标签页里面按时间顺序列出了所有往返的消息。过滤技巧如果连接太多可以使用Focus功能。基于 Path 过滤在握手请求的Path上右键选择FocusCharles 会自动创建一个过滤器只显示该路径的连接。基于 Header 过滤如果握手请求带有特定的 Header如X-Auth-Token你也可以在Proxy - Recording Settings - Include中添加基于该 Header 值的过滤规则。4. 代码示例构造带鉴权 Header 的 WebSocket 连接有时服务端会验证握手阶段的 Header。下面是一个 Python 客户端示例展示如何建立这样的连接。import asyncio import websockets async def connect_to_websocket(): # 定义 WebSocket 服务器地址 uri wss://your-websocket-server.com/chat # 构造自定义的握手 Headers custom_headers { X-Auth-Token: your_secret_token_here, # 必须设置此Header以通过服务端鉴权 User-Agent: MyDebugClient/1.0, Origin: https://your-app-domain.com # 根据CORS策略可能需要设置 } try: # 建立连接传入自定义headers async with websockets.connect(uri, extra_headerscustom_headers) as websocket: print(WebSocket 连接成功) # 发送一条文本消息 await websocket.send(Hello, Server!) print(f已发送: Hello, Server!) # 接收服务器响应 response await websocket.recv() print(f收到回复: {response}) except websockets.exceptions.InvalidStatusCode as e: print(f连接失败状态码: {e.status_code}) except Exception as e: print(f发生错误: {e}) # 运行客户端 asyncio.run(connect_to_websocket())在 Charles 中抓包这个连接你就能在初始的GET握手请求中清晰地看到我们设置的X-Auth-Token等 Header这对于调试鉴权问题非常有用。5. 安全实践调试中的“红线”抓包工具能力强大但也伴随风险尤其在接近生产环境时。风险控制绝对不要在连接着公网或生产环境网络的情况下随意安装调试证书并开启全局代理。这可能导致你的所有流量包括银行、邮件被中间人窃听。最佳实践是搭建独立的测试环境或使用仅指向测试服务的代理规则避免使用*:*。数据脱敏如果抓取的日志或消息中包含用户敏感信息手机号、身份证号、Token在保存或分享 Session 文件前应使用 Charles 的Map Local或Rewrite功能对敏感字段进行脱敏处理或直接删除该 Session 文件。6. 避坑指南常见问题与解决连接失败提示 SSL/TLS 错误这是最常见的问题。99% 的原因是证书未正确信任。请严格按照 3.2 步骤检查特别是 iOS/Android 设备务必去系统设置里确认 Charles 根证书已被“完全信任”。也可以尝试在 Charles 的SSL Proxying Settings中暂时取消Enable SSL Proxying看wss://连接是否降级为ws://能通以此排查证书问题。WebSocket 消息显示为乱码或二进制如果传输的是二进制帧如图片、音频数据Charles 默认会以十六进制显示。你可以尝试在 WebSocket 消息视图上方点击Text或Binary按钮切换查看方式。对于已知格式如 Protobuf可以寻找或编写 Charles 插件进行解析。抓不到任何流量检查设备代理设置是否正确IP和端口检查 Charles 的Proxy - macOS Proxy或External Proxy Settings是否意外启用关闭电脑和手机的防火墙试一下。7. 延伸思考不止于 WebSocket掌握了 Charles 抓取 WebSocket 的技能后你的调试能力已经上了一个台阶。你可以尝试挑战更复杂的场景MQTT over WebSocket物联网常用的 MQTT 协议也常基于 WebSocket 传输。抓包流程完全一样只是应用层协议不同。你需要结合 MQTT 协议知识来分析消息内容。Socket.IO一个流行的实时库它在 WebSocket 基础上封装了自己的心跳、事件和房间机制。抓包时你会看到一些ping/pong帧和特定格式的message帧需要对照 Socket.IO 协议格式进行解析。调试是开发的另一面镜子能让我们更清晰地看到数据流动的轨迹。通过 Charles 这把“瑞士军刀”我们得以透视 WebSocket 这个实时通道的内部从而更高效地定位问题、验证逻辑。整个调试过程让我对实时通信的底层链路有了更直观的认识。这让我想起如果想更深入地体验和创造实时语音对话应用完全可以基于成熟的云服务来快速搭建。例如通过火山引擎提供的各类 AI 模型服务你可以像搭积木一样组合语音识别、大语言模型和语音合成能力打造属于自己的实时通话 AI 应用。我最近就尝试了这样一个名为从0打造个人豆包实时通话AI的动手实验它清晰地展示了如何将“听、想、说”三个环节串联起来形成完整的交互闭环。对于想了解实时语音应用全貌的开发者来说这是个非常直观的入门途径步骤清晰自己跟着操作一遍就能把理论变成看得见、听得着的实际应用。