Debug / Inspect WebSocket traffic with Fiddler【转】

简介: Introduction      I have recently written a project using SignalR, which supports HTML 5 WebSocket.  However I cannot find good tools to debug or inspect WebSocket traffic.

Introduction     

I have recently written a project using SignalR, which supports HTML 5 WebSocket.  However I cannot find good tools to debug or inspect WebSocket traffic. I know that both Chrome and Fiddler support inspecting the WebSocket traffic, but they are very basic. If you have very high volume of traffic or each frame is very large, it becomes very difficult to use them for debugging. (Please see more details in the Background section). 

I am going to show you how to use Fiddler (and FiddlerScript) to inspect WebSocket traffic in the same way you inspect HTTP traffic. This technique applies to all WebSocket implementations including SignalR, Socket.IO and raw WebSocket implementation, etc.

 

 

Background  

Limit of Chrome traffic inspector: 

  • WebSocket traffic is shown in Network tab -> "connect" packet (101 Switching Protocols) -> Frame tab. WebSocket traffic does not automatically refresh unless you click on the 101 packet again.
  • It does not support "Continuation Frame", as shown below: 

 

Limit of Fiddler Log tab: 

  • WebSocket traffic frames in the Fiddler Log tab are not grouped, therefore it is hard to navigate between frames.  
  • Continuation frames are not decoded, they are displayed as binary.  
  • In addition, if you have very high volume of traffic, Fiddler will use up 100% of your CPU and hang.  

 

  • Hint: Fiddler no longer spews WebSocket messages to the Log tab by default.
    You can do so using FiddlerScript. Simply click Rules > Customize
    Rules and add the following function inside your Handlers class:
static function OnWebSocketMessage(oMsg: WebSocketMessage) {
    // Log Message to the LOG tab
    FiddlerApplication.Log.LogString(oMsg.ToString());
}  

Solution     

With this solution, you get all following benefits: 

 

  • You can see all WebSocket frames in Fiddler main window, and you can navigate between frames easily.  
  • You can see the frame details in the Inspector tab -> Request info -> JSON sub-tab.
  • Continuation frames are automatically decoded and combined together.
  • All frames are captured and displayed in Fiddler main window automatically without manual reload.
  • CPU usage for Fiddler will still be low for high volume of traffic.

 


How it works? 

1. Download Fiddler Web Debugger (v4.4.5.9) 

2. Open Fiddler -> Rules -> Customize Rules... ->This will open the FiddlerScript

3. Add following codes FiddlerScript:

import System.Threading;

// ...

class Handlers
{
    // ...
    static function Main() { // ... // // Print Web Socket frame every 2 seconds // printSocketTimer = new System.Threading.Timer(PrintSocketMessage, null, 0, 2000); } // Create a first-in, first-out queue static var socketMessages = new System.Collections.Queue(); static var printSocketTimer = null; static var requestBodyBuilder = new System.Text.StringBuilder(); static var requestUrlBuilder = new System.Text.StringBuilder(); static var requestPayloadIsJson = false; static var requestPartCount = 0; // // Listen to WebSocketMessage event, and add the socket messages // to the static queue. // static function OnWebSocketMessage(oMsg: WebSocketMessage) { Monitor.Enter(socketMessages); socketMessages.Enqueue(oMsg); Monitor.Exit(socketMessages); } // // Take socket messages from the static queue, and generate fake // HTTP requests that will be caught by Fiddler. // static function PrintSocketMessage(stateInfo: Object) { Monitor.Enter(socketMessages); while (socketMessages.Count > 0) { var oMsg = socketMessages.Dequeue(); ExtractSocketMessage(oMsg); } Monitor.Exit(socketMessages); } // // Build web socket message information in JSON format, and send this JSON // information in a fake HTTP request that will be caught by Fiddler // // If a frame is split in multiple messages, following function will combine // them into one // static function ExtractSocketMessage(oMsg: WebSocketMessage) { if (oMsg.FrameType != WebSocketFrameTypes.Continuation) { var messageID = String.Format( "{0}.{1}", oMsg.IsOutbound ? "Client" : "Server", oMsg.ID); var wsSession = GetWsSession(oMsg); requestUrlBuilder.AppendFormat("{0}.{1}", wsSession, messageID); requestBodyBuilder.Append("{"); requestBodyBuilder.AppendFormat("\"doneTime\": \"{0}\",", oMsg.Timers.dtDoneRead.ToString("hh:mm:ss.fff")); requestBodyBuilder.AppendFormat("\"messageType\": \"{0}\",", oMsg.FrameType); requestBodyBuilder.AppendFormat("\"messageID\": \"{0}\",", messageID); requestBodyBuilder.AppendFormat("\"wsSession\": \"{0}\",", wsSession); requestBodyBuilder.Append("\"payload\": "); var payloadString = oMsg.PayloadAsString(); if (oMsg.FrameType == WebSocketFrameTypes.Binary) { payloadString = HexToString(payloadString); } if (payloadString.StartsWith("{")) { requestPayloadIsJson = true; } else { requestBodyBuilder.Append("\""); } requestBodyBuilder.AppendFormat("{0}", payloadString); } else { var payloadString = HexToString(oMsg.PayloadAsString()); requestBodyBuilder.AppendFormat("{0}", payloadString); } requestPartCount++; if (oMsg.IsFinalFrame) { if (!requestPayloadIsJson) { requestBodyBuilder.Append("\""); } requestBodyBuilder.AppendFormat(", \"requestPartCount\": \"{0}\"", requestPartCount); requestBodyBuilder.Append("}"); SendRequest(requestUrlBuilder.ToString(), requestBodyBuilder.ToString()); requestBodyBuilder.Clear(); requestUrlBuilder.Clear(); requestPayloadIsJson = false; requestPartCount = 0; } } // // Generate fake HTTP request with JSON data that will be caught by Fiddler // We can inspect this request in "Inspectors" tab -> "JSON" sub-tab // static function SendRequest(urlPath: String, message: String) { var request = String.Format( "POST http://fakewebsocket/{0} HTTP/1.1\n" + "User-Agent: Fiddler\n" + "Content-Type: application/json; charset=utf-8\n" + "Host: fakewebsocket\n" + "Content-Length: {1}\n\n{2}", urlPath, message.Length, message); FiddlerApplication.oProxy.SendRequest(request, null); } // // Unfortunately, WebSocketMessage class does not have a member for // Web Socket session number. Therefore, we are extracting session number // from its string output. // static function GetWsSession(oMsg: WebSocketMessage) { var message = oMsg.ToString(); var index = message.IndexOf("."); var wsSession = message.Substring(0, index); return wsSession; } // // Extract Hex to String. // E.g., 7B-22-48-22-3A-22-54-72-61-6E to {"H":"TransportHub","M":" // static function HexToString(sourceHex: String) { sourceHex = sourceHex.Replace("-", ""); var sb = new System.Text.StringBuilder(); for (var i = 0; i < sourceHex.Length; i += 2) { var hs = sourceHex.Substring(i, 2); sb.Append(Convert.ToChar(Convert.ToUInt32(hs, 16))); } var ascii = sb.ToString(); return ascii; } } 

 

4. Setup Fiddler -> AutoResponder (Optional)

 

I have tested with Firefox 25.0, IE 11.0, Chrome 32.0. This solution should work with all browsers that support WebSocket, as long as the network proxy is setup correctly. Using IE as an example:

  1. Open Fiddler, this will setup the network proxy automatically, but it's not enough.
  2. Open IE -> Tools -> Internet Options -> Connections tab -> Click "LAN settings" button
  3. Click "Advanced" button
  4. Tick "Use the same proxy server for all protocols" checkbox.

Points of Interest  

  1. You can test above solution by going to http://www.websocket.org/echo.htmlhttp://socket.io/demos/chat/and https://jabbr.net/ (log-in required. This site is built using SignalR, which supports WebSocket).
  2. Above code is printing WebSocket frames every 2 seconds to avoid high CPU usage, which means the timestamps in Statistics tab may be delayed for up to 2 seconds. You may adjust this timer depending on your traffic volume. 
    • However, you can see the actual time when the frame is received, in the Inspector tab -> Request info -> JSON sub-tab -> doneTime.
  3. For simplicity, I have only created one Queue for all WebSocket sessions, Continuation frames are combined together regardless of their session ID. Feel free to extend my code. For now, just debug one WebSocket session at a time.
  4. Above code assumes that payload starts with '{' is JSON data, this works very well for me. If this assumptionis wrong in your situation, you can easily modify the code.
  5. Note: Socket.IO currently prefix a special meaning number before the payload, which makes the frames invalid JSON data, i.e., you cannot see nice formatted frames in JSON sub-tab. You can however still see the frames in Raw sub-tab. Alternatively, you can update my script to handle the number prefix from Socket.IO.
  6. Please vote my article if you find it useful. Thanks for your support.

 

http://www.codeproject.com/Articles/718660/Debug-Inspect-WebSocket-traffic-with-Fiddler

技术改变世界! --狂诗绝剑
目录
相关文章
|
数据采集 监控 算法
原子钟的基本介绍
【10月更文挑战第7天】本文介绍原子钟是一种利用原子跃迁频率作为基准的高精度计时设备,广泛应用于通信、导航、科学研究等领域。铯原子钟是最精确的计时设备之一,基于铯133原子的超精细跃迁,频率为9,192,631,770 Hz。其关键部件包括铯束源、微波腔、磁态选择器、检测系统和反馈回路。原子钟在GPS、电信、金融市场等应用中至关重要,软件开发需考虑高精度时间同步、数据处理、硬件接口和性能监控。
1260 60
|
Java 定位技术 API
标准坐标系与火星坐标系(高德)百度坐标系之间互转
这里先给大家介绍几个坐标系: 1.WGS84:国际坐标系,为一种大地坐标系,也是目前广泛使用的GPS全球卫星定位系统使用的坐标系。2.GCJ02:火星坐标系,是由中国国家测绘局制订的地理信息系统的坐标系统。
4222 0
基于MPPT最大功率跟踪和SVPWM的光伏三相并网逆变器simulink建模与仿真
本课题基于Simulink建模与仿真,研究了光伏三相并网逆变器。系统包括PV模块、MPPT模块、SVPWM模块和电网模块。通过MPPT确保光伏阵列始终工作在最大功率点,SVPWM生成高质量的三相电压输出,提高能量转换效率。仿真结果展示了不同光照条件下系统的输出电压、功率及并网性能。核心程序基于MATLAB2022a实现。
|
供应链 网络协议 数据安全/隐私保护
|
监控 Oracle 关系型数据库
"深度剖析:Oracle SGA大小调整策略——从组件解析到动态优化,打造高效数据库性能"
【8月更文挑战第9天】在Oracle数据库性能优化中,系统全局区(SGA)的大小调整至关重要。SGA作为一组共享内存区域,直接影响数据库处理能力和响应速度。本文通过问答形式介绍SGA调整策略:包括SGA的组成(如数据缓冲区、共享池等),如何根据负载与物理内存确定初始大小,手动调整SGA的方法(如使用`ALTER SYSTEM`命令),以及利用自动内存管理(AMM)特性实现智能调整。调整过程中需注意监控与测试,确保稳定性和性能。
937 2
|
Linux 网络安全 Android开发
Termux-远程管理Linux服务器
在手机上通过termux管理Linux服务器
1670 0
|
存储 算法 Java
图的操作和应用之景区信息管理系统(数据结构课程设计)
0001:图的操作和应用之景区信息管理系统(C++版数据结构课程设计) 现有一个景区,景区里面有若干个景点,景点之间满足以下条件: (1) 某些景点之间铺设了道路(相邻) (2) 这些道路都是可以双向行驶的(无向图) (3) 从任意一个景点出发都可以游览整个景区(连通图) 开发景区信息管理系统,对景区的信息进行管理。使用图的数据结构来保存景区景点信息,为用户提供创建图、查询景点信息、旅游景点导航、搜索最短路径、铺设电路规划等功能。 文章目录0001:图的操作和应用之景区信息管理系统(C++版数据结构课程设
图的操作和应用之景区信息管理系统(数据结构课程设计)
|
Java API 开发工具
SpringBoot助力!轻松实现微信模版消息推送
SpringBoot助力!轻松实现微信模版消息推送
|
Linux C语言
centos 7 下使用高版本gcc编译安装
centos 7 下使用高版本gcc编译安装
559 0
|
机器学习/深度学习 人工智能 并行计算
研发为底、生态为径、AI为翼——全国一体化算力算网调度平台正式发布
研发实力是一家芯片设计公司的核心竞争力,英伟达从发展初期就重视研发生产力,以高投入换取高回报不断提升产品竞争力。2005 年,AMD 的研发费用为 11 亿美元,是英伟达的 3.2 倍左右。而到了 2022 年,英伟达的研发费用达到 73.4 亿美元,是 AMD 的 1.47 倍。
1207 0