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:

Hide   Shrink    Copy Code
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

Debug / Inspect WebSocket traffic with Fiddler【转】的更多相关文章

  1. How To: Capture Android & iOS Traffic with Fiddler

    How To: Capture iOS Traffic with Fiddlerhttps://www.telerik.com/blogs/how-to-capture-ios-traffic-wit ...

  2. Cannot capture jmeter traffic in fiddler

    Cannot capture jmeter traffic in fiddler First, change Fiddler's port back to 8888 as it was origina ...

  3. 两步让你的mobile traffic通过fiddler代理传送

    mobile app运行时由于调试网络相关的内容非常不便,所以如果能够让iphone通过桌面主机来跑traffic,那么在pc上就能非常清楚地检查mobile app和后端之间有什么问题了. 幸运的是 ...

  4. [Debug] Inspect and Style an Element in DevTools that Normally Disappears when Inactive

    It’s handy to inspect an element in your browser’s DevTools when you need to experiment or tweak it’ ...

  5. 使用Chrome或Fiddler抓取WebSocket包

    首先,HTTP是建立在TCP协议基础上的,而WebSocket通常也是建立在TCP上,所以说为什么有些网页游戏抓不到包而有些又可以,这仅是因为你使用的抓包工具是针对了HTTP的通信协议. 我先从抽象的 ...

  6. Microsoft ASP.NET SignalR

    SignalR类似与JavaScript实时框架,如Socket.IO.SignalR能够完成客户端向服务器的异步通信,并同时支持服务器向浏览器客户端推送事件.SignalR的连接通过日益流行的Web ...

  7. Fiddler抓包和修改WebSocket数据,支持wss

    记录一下用Fiddler对WebSocket收发的数据进行抓包分析和篡改数据,只找到这么一个方法,能用就行吧. 时间:2019-3-29 环境: win7 + Fiddler 5.0 Fiddler抓 ...

  8. 【转】Fiddler抓包和修改WebSocket数据,支持wss

    记录一下用Fiddler对WebSocket收发的数据进行抓包分析和篡改数据,只找到这么一个方法,能用就行吧.时间:2019-3-29环境: win7 + Fiddler 5.0 Fiddler抓取W ...

  9. Fiddler Web Debugger Tool

    The Fiddler tool helps you debug web applications by capturing network traffic between the Internet ...

随机推荐

  1. 【JS学习笔记】函数传参

    比如仅仅改变背景的颜色 函数传参:参数就是占位符. 那么在什么时候用传参呢?函数里定不下来的东西. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1 ...

  2. 办理康卡迪亚大学(本科)学历认证『微信171922772』Concordia学位证成绩单使馆认证Concordia University

    办理康卡迪亚大学(本科)学历认证『微信171922772』Concordia学位证成绩单使馆认证Concordia University Q.微信:171922772办理教育部国外学历学位认证海外大学 ...

  3. java基础练习 7

    public class Seventh { public static void main(String[] args){ double x=0,a=1,b=9; while(x!=a*a-100& ...

  4. elasticsearch最佳实践

    创建索引 无mapping 创建索引名称为index的索引 curl -XPUT http://localhost:9200/book 有mapping 如果需要定义每个类型的结构映射,创建type名 ...

  5. 时间序列 预测分析 R语言

    在对短期数据的预测分析中,我们经常用到时间序列中的指数平滑做数据预测,然后根据不同. 下面我们来看下具体的过程 x<-data.frame(rq=seq(as.Date('2016-11-15' ...

  6. javascript 事件委托 和jQuery事件绑定on、off 和one

    一. 事件委托什么是事件委托?用现实中的理解就是:有100 个学生同时在某天中午收到快递,但这100 个学生不可能同时站在学校门口等,那么都会委托门卫去收取,然后再逐个交给学生.而在jQuery 中, ...

  7. Cracking the Coding Interview 第一章

    第一章:数组与字符串 1 数组与字符串 请实现一个算法,确定一个字符串的所有字符是否全都不同.这里我们要求不允许使用额外的存储结构. 给定一个string iniString,请返回一个bool值,T ...

  8. wifi 模块

    #include"STC12C5A.H" #include <string.h> #include<intrins.h> #define uint unsi ...

  9. linux 下查看cpu是几核的

    几个cpu more /proc/cpuinfo |grep "physical id"|uniq|wc -l 每个cpu是几核(假设cpu配置相同) more /proc/cpu ...

  10. 解决vs2013下创建的python文件,到其他平台(如linux)下中文乱码(或运行时报SyntaxError: (unicode error) 'utf-8' codec can't decode byte...)

    Vs2013中创建python文件,在文件中没输入中文时,编码为utf-8的,如图 接着,在里面输入几行中文后,再次用notepad++查看其编码如下,在vs下运行也报错(用cmd运行就不会): 根据 ...