☰
FiddlerCore抓包引擎:SDK集成、HTTPS解密与流量拦截实战
2026/10/8 9:04:54 网站建设 项目流程

简介:这是一份基于FiddlerCore封装的开源抓包工具源码,适合需要HTTP/HTTPS会话捕获与调试的.NET开发人员。资源以zip形式发布,共33个文件,核心为11个C#源码文件、4个DLL运行库及4个EXE示例程序,并附带必要的配置文件、文本说明和调试符号。代码支持两种抓包方式:通过系统代理进入,以及通过自定义WebProxy启动独立代理端口,并包含证书管理和自动化操作辅助类,参考了社区常见FiddlerCore示例加以整合。压缩包整体仅717KB,结构清晰,便于学习和二次修改。已有1577人学习下载,适合正在寻找免费FiddlerCore抓包方案、想快速集成代理抓包功能或理解证书处理流程的开发者参考。

1. FiddlerCore抓包:抓包引擎不一定要开着图形界面

大多数人提到 FiddlerCore,第一反应是“那个能抓包的工具”,再仔细看一眼就又绕回去开图形界面了。我在做接口自动化测试平台时遇到一个很实际的问题:CI 环境里跑用例,请求出错时想留一份当时的完整流量,图形界面里那条请求早就被新流量冲走了,靠人盯根本盯不住。FiddlerCore 解决的就是这个问题——它把抓包引擎本身打包成一个可引用的 SDK,让你在自己的进程里直接起一个代理内核,流量进来、出去、改什么、放行还是丢弃,全由代码决定,不依赖那个黑匣子一样的 GUI。这篇文章写给正在搭流量录制回放、接口自动化、本地调试工具的人,目标是让你看完就能把 FiddlerCore 接入到自己的项目里。

2. FiddlerCore是一个SDK,不是Fiddler的另一个壳

2.1 事件驱动的代理内核:FiddlerCore到底怎么工作

理解 FiddlerCore,先要把“抓包”拆成两个动作:一是把网络流量引导过来,二是对流量的内容做处理。FiddlerCore 做的事是在你的程序里起一个 HTTP 代理端点,然后通过把系统代理指到这个端点,让本机或同局域网设备的 HTTP/HTTPS 流量都从它这里经过。它不做界面,而是把每个经过的请求和响应包装成一个 Session 对象,然后触发你挂上的事件回调。

为什么采用事件而不是阻塞队列?因为抓包场景里很多操作是“要赶在流量真正发出去之前做完”的,比如往请求头里注入一串测试标识、把某个线上接口的响应替换成本地 Mock 数据。如果用一个队列把流量先收起来再让业务代码轮询,就很难做到“改完再放行”这种实时性。事件回调模型让业务代码在请求发出前、响应返回前、完整会话结束时各有一个介入点,这也是 FiddlerCore 和单纯用 Socket 写代理之间最根本的差别。

2.2 最小可用接入:三行初始化和一个回调

先看一段能跑起来的最小代码,这是 FiddlerCore 最常见的接入骨架:

using Fiddler; var settings = new FiddlerCoreStartupSettingsBuilder() .ListenOnPort(8888) // 代理监听端口 .RegisterAsSystemProxy(true) // 注册为系统代理,接管本机流量 .DecryptHTTPS(true) // 解密 HTTPS,先决条件是安装根证书 .OptimizeThreads(true) // 让 FiddlerCore 根据 CPU 核数调线程池 .Build(); FiddlerApplication.BeforeRequest += OnBeforeRequest; // 请求发出前 FiddlerApplication.BeforeResponse += OnBeforeResponse; // 响应返回前 FiddlerApplication.AfterSessionComplete += OnAfterSessionComplete; // 会话结束 FiddlerApplication.Start(settings); // 程序退出前 FiddlerApplication.Shutdown();

这段代码里有几个参数直接影响抓包结果。ListenOnPort 是代理服务监听的端口,手机抓包时后续要让手机把代理指向这个端口,所以端口要选一个不被占用的固定值,我一般用 8888,如果用 8888 被别的服务占了就改用 8899。RegisterAsSystemProxy(true) 的含义是自动修改操作系统的代理设置,让本机所有走 HTTP/HTTPS 的流量都进入 FiddlerCore,这一步如果为 false,就只能手动去给单个客户端配代理。OptimizeThreads(true) 在多并发请求的场景下很有用,FiddlerCore 线程模型默认偏保守,改成 true 之后高并发会话的处理能力明显好一些。

回调方法里的参数都是 Session 对象,它是理解和操作流量的入口。BeforeRequest 表示请求还没发出去,这时可以改头部、改请求体甚至直接构造一个假响应返回;BeforeResponse 表示响应已经从目标服务器拿到但还没回到客户端,适合修改响应体或做重试逻辑;AfterSessionComplete 表示整个会话已经走完,适合做流量留痕和统计。

2.3 会话对象与请求响应的数据入口

Session 对象是 FiddlerCore 里最关键的类,几乎所有有用的信息都从它里面取。我常用的数据入口就三类:请求信息、响应信息、会话标记。

private void OnAfterSessionComplete(Session oSession) { // 请求侧 var url = oSession.fullUrl; // 完整URL,含query string var reqHeaders = oSession.oRequest.headers; // 请求头集合 var reqBody = oSession.RequestBody; // 请求体,字节数组 // 响应侧 var respStatus = oSession.responseCode; // HTTP状态码 var respBodyBytes = oSession.ResponseBody; // 响应体字节 // 自定义标记:写在请求头上的调试信息 var token = oSession["X-Debug-Token"]; }

注意 oHeaders 和 oRequest.headers 的区别,前者是请求头对象,后者才是真正从线上拿到的原始请求头,修改时要基于 oSession.oRequest 去改。RequestBody 和 ResponseBody 在 FiddlerCore 里默认返回字节数组,用 Encoding.UTF8.GetString() 转字符串做解析即可,不要直接调 ToString(),拿到的类型名而不是内容。

这里还要提一个容易理解错的地方:BeforeRequest 里读取请求体时,如果内容较大,FiddlerCore 可能还没有把整个请求体读取完。这时要读 Body,建议先调用 oSession.utilLoadRequest(),它会把请求体完整加载进内存并返回字节数组。同样,BeforeResponse 里读响应体先调用 oSession.utilLoadResponse() 再取 ResponseBody,能避开不少“读出来是空串”的问题。

3. 抓包前的三个必调开关:端口、系统代理与HTTPS证书

3.1 端口与系统代理的关系,以及端口被占的排查

端口和系统代理看似是两个独立配置,实际是一条链路上两个必须同时满足的条件。代理端口起不来,后面什么都没得抓;端口起来了但系统代理没配上,只有手动把客户端流量指过来才有效。我的经验是按端口、系统代理、证书三个顺序做基础配置排查。

端口被占用是最常见的翻车点。FiddlerCore 的 Start 方法在端口被占时会直接抛异常,但有些情况下异常信息比较隐晦,我建议在启动 FiddlerCore 之前主动做一次端口探测:

using System.Net; using System.Net.Sockets; public static bool IsPortAvailable(int port) { try { var listener = new TcpListener(IPAddress.Loopback, port); listener.Start(); listener.Stop(); return true; } catch (SocketException) { return false; } } // 启动代理前 if (!IsPortAvailable(8888)) { throw new InvalidOperationException("端口8888被占用,请换端口或释放占用进程"); }

这段代码的关键不是检测本身,而是把“选端口”变成一个确定性动作。写死端口第一次可能没事,跑久了容易和别的开发工具冲突,尤其有些本地服务会随机扫端口,我后来干脆做一个端口分配表,把 8888-8899 划成 FiddlerCore 专用段,启动时顺序找一个可用端口。

RegisterAsSystemProxy(true) 这个开关也要单独说。它改的是 Windows 系统代理设置,程序退出时 FiddlerCore 的 Shutdown 方法会尝试恢复原系统代理,但如果进程是被强杀的,系统代理可能停留在指向 8888 端口的状态。这时你会发现浏览器突然上不了网,因为代理指向的端口已经没人监听了。碰到这种情况,去系统设置里把代理关闭,或者手动恢复原代理地址即可,这是 FiddlerCore 接入原生应用中一个非常经典的现场问题。

3.2 HTTPS解密三件套的设置顺序:证书、DecryptHTTPS、回调

HTTPS 解密是 FiddlerCore 使用中被误解最多的部分。不少人以为设置了 DecryptHTTPS(true) 就能抓 HTTPS,结果打开抓包一看全是 CONNECT 隧道,看不到任何明文内容。原因很简单:FiddlerCore 要做中间人解密,客户端必须信任 FiddlerCore 持有的根证书,否则 TLS 握手在客户端就失败了,要么连接直接断掉,要么客户端报证书错误。

根证书的生成和安装一般在 Start 之前完成:

// 1. 先确保根证书存在 if (!FiddlerApplication.CertificateMaker.CheckForExistingRootCertificate()) { FiddlerApplication.CertificateMaker.CreateRootCertificate(); } // 2. 安装到当前用户信任区 FiddlerApplication.CertificateMaker.InstallCertificate(); // 3. 再启动代理并开启解密 FiddlerApplication.Start(settings);

这个顺序不能乱。CertificateMaker 是 FiddlerCore 提供的一个证书操作入口,CreateRootCertificate 会在本机生成一个根证书,生成之后系统并不知道这张证书是可信的,必须 InstallCertificate() 把它装进受信任的根证书颁发机构。如果跳过安装直接 Start,客户端发起的 TLS 握手会因为“证书不受信任”而失败,表现就是抓不到 HTTPS 请求或者客户端直接报错。

还有一个小坑:InstallCertificate 需要在程序有权限的环境下执行,如果用普通权限跑,安装证书会失败或只装到当前用户下。Linux 服务器上跑 FiddlerCore 时,证书要装到 /etc/ssl/certs 这种系统级信任区,和 Windows 的行为不一样,做跨平台部署时要先确认目标环境的证书信任机制。

3.3 只抓不解密:透明代理与DoNotDecrypt的使用边界

不是所有场景都需要解密 HTTPS。如果你只是想统计请求量、记录 URL、看状态码分布,解密反而会带来额外的 CPU 开销和证书风险。FiddlerCore 里有透明的转发模式,让流量原样穿过,不解密、不改写,这种方式在抓包服务里相当于只做一个“流量镜像口”。

var settings = new FiddlerCoreStartupSettingsBuilder() .ListenOnPort(8888) .RegisterAsSystemProxy(true) .DecryptHTTPS(false) // 抓包但不解密 .Build();

DecryptHTTPS(false) 时,HTTPS 请求的 URL 和域名还能看到,但请求体响应体全是密文。这个模式适合做流量采样统计,因为不用安装证书,接入成本低,也不会有证书信任问题。而一旦业务需要修改请求或响应的内容,必须把解密打开,同时接受“证书安装 + 客户端信任”这两个前置条件。

还有个容易被忽略的选项叫 DoNotMakeChanges。开启后 FiddlerCore 会减少对会话内容的改动,比如不会主动给请求加头,这在某些后端对请求头敏感的场景下很关键。默认情况下 FiddlerCore 可能会在某些版本里加入自己的代理痕迹头,如果你的目标是做一个尽可能“不被发现”的抓包旁路,把 DoNotMakeChanges 设为 true 能减少一层干扰。

4. 移动App与小程序抓包:把FiddlerCore变成手机代理

4.1 手机代理指向PC:最小配置

把 FiddlerCore 用在手机 App 抓包,本质是让手机上的流量经过同一台 PC 上的代理端口。电脑上 FiddlerCore 监听 8888,手机连同一个局域网,代理设置里把主机指向电脑 IP、端口设为 8888,HTTP 流量就会自动被 FiddlerCore 接管。

但 HTTPS 解密在手机上有一个额外环节:手机必须信任 FiddlerCore 生成的根证书。证书不能只装在电脑上,要导出后传到手机安装。Android 和 iOS 的安装路径不同,Android 上是把证书导入到“CA 证书”或“用户凭据”,iOS 上是安装到描述文件然后在设置里打开证书信任开关。这个环节最容易遇到的问题,就是手机上安装证书以后依然抓不到 HTTPS 明文,这时要检查证书是否完整安装、日期是否正确、以及手机代理是否真的走通了。

手机抓包还有一个时间点要注意:代理设置后,已经建立的连接不会立刻切换到新代理。微信、支付宝这类长连接 App,往往是打开时建立连接,后面一直复用,所以设置完代理后要么切换 App 页面触发新请求,要么彻底杀掉 App 进程再重开。否则你看着代理配置没问题,就是等不到流量。

4.2 微信小程序与内嵌WebView的特殊抓包姿势

小程序抓包这两年问得很多,一个现实情况是:小程序的流量从微信进程发出去,而不是从小程序独立进程发出去。所以抓包工具能不能抓到小程序的包,既取决于代理是否生效,也取决于微信自身是否信任你安装的证书。

微信在这方面限制比较严。iOS 上的微信对于 HTTPS 请求,很多版本会内置证书校验逻辑,即使你在系统层面安装了 FiddlerCore 的根证书,TLS 握手依然可能失败。Android 上相对宽松,但 Android 7 以后默认不再信任用户安装的 CA 证书,只有系统证书才被信任,所以手机抓包经常出现“安装了证书依然解密失败”的玄学问题。常见做法是把用户证书移动到系统证书目录,这需要手机已经 root 或者能解锁 bootloader。

另外一个更隐蔽的坑是 WebView 代理行为。App 里内嵌的 WebView 有些不走系统代理设置,而是使用 App 代码里单独配置的网络库策略。这种情况下,即使你给手机设置了代理,小程序的页面和 WebView 的请求也可能完全不进来。排查时可以先确认一个普通的浏览器请求是否被抓到,如果浏览器能抓到而 App 抓不到,说明问题出在 App 的网络栈对代理的适配,而不是代理配置本身。

4.3 遇到App的证书校验怎么办?调试允许和边界

业务 App 为了防止中间人攻击,会在代码里做证书绑定(Certificate Pinning),即使系统信任了你的根证书,App 依然不认账,表现是连接失败或者直接报错。对于开发者自己维护的测试 App,团队内部常见的做法是给测试包做一个开关,校验失败时放行;对于第三方 App,社区里也有不少辅助调试插件可以在测试机上临时绕过校验。

这里必须说一个边界:这些手段只允许用于你有权调试的设备,比如自己公司的测试机、自己开发的 App。对没有授权的流量做中间人解密,不仅技术上困难,法律上也有明确的合规红线。我在这类问题上只做一件事:先用普通浏览器的流量验证 FiddlerCore 解密链路是通的,再判断问题出在证书链路还是 App 的主动校验上。如果链条本身不通,先修系统设置,不要急着上绕过方案。

5. FiddlerCore抓包常见问题与避坑记录

5.1 坑一:什么都抓不到,先查系统代理和端口

现象:FiddlerCore 启动了,控制台不报错,但请求日志里一条流量都没有。

原因:大概率是系统代理没有真正生效,或者网络流量本来就请求了别的代理。还有一种情况是代理启动时端口被某个未知进程抢占了但异常被吞掉。

解决:先确认监听端口正常:用 netstat -ano | findstr 8888 看端口是否处于 LISTEN。再查系统代理:Windows 设置里看代理指向的地址和端口是否一致。最后用浏览器访问一个普通 HTTP 网站,如果浏览器能抓到流量,就排除代理链路问题,再去查 App 自身是否用了自定义网络栈。

5.2 坑二:只有CONNECT隧道,没有解密后的内容

现象:抓包记录里大量 CONNECT 开头的会话,没有真正的请求头和响应体。

原因:CONNECT 是 HTTPS 代理握手中的第一步,说明客户端和代理之间连接成功了,但后续的 TLS 握手没有成功,或者 DecryptHTTPS 配置是 false。

解决:先把 DecryptHTTPS 确认为 true,再检查根证书是否已安装且被客户端信任。手机场景下要额外确认证书装进了系统信任区。如果证书没问题,还出现 CONNECT,抓一下 TLS 握手失败的具体报文,通常是证书颁发者不被信任导致的。

5.3 坑三:改请求体后Content-Length没重算

现象:在 BeforeRequest 回调里改了请求体内容,结果请求发出去后服务端报 400 或请求参数读不出来。

原因:改了请求体字节数,但没有同步修改 Content-Length 请求头,后端按旧长度截取或拼接请求体,导致数据错位。

解决:每次修改完请求体,强制重写 Content-Length:

private void OnBeforeRequest(Session oSession) { var newBody = "{ \"debug\": 1 }"; oSession.RequestBody = Encoding.UTF8.GetBytes(newBody); oSession.oRequest.headers["Content-Length"] = oSession.RequestBody.Length.ToString(); }

这里有个细节:一旦给 RequestBody 赋值,FiddlerCore 内部的请求体状态会更新,但 Header 不会自动跟着变,必须手动同步 Content-Length。同理,修改响应体后也要处理响应头的 Content-Length。

5.4 坑四:长时间驻留后内存与句柄持续增长

现象:FiddlerCore 作为服务跑几天后,内存占用翻倍,甚至出现句柄耗尽导致代理假死。

原因:很多会话对象在回调执行完后没有被释放,或者某些响应流没有被读取完全导致连接资源无法回收。FiddlerCore 在高并发下如果不对 Session 对象做留存管理,内存增长几乎必然发生。

解决:两个策略并行。一是回调里做到“用完即走”,需要留存的字段提取到业务实体里,不要保存整个 Session 对象。二是限制请求体响应体的自动加载,绝大多数分析场景只需要头和部分 Body:

private void OnAfterSessionComplete(Session oSession) { var respBody = string.Empty; if (oSession.ResponseBody.Length < 10 * 1024) // 只保留小于10KB的Body { respBody = Encoding.UTF8.GetString(oSession.ResponseBody); } // 存到自己的存储里,然后让 oSession 走人 }

关键的认知是 Session 对象本身不小,里面持有着完整的请求头、响应头、Body 字节数组。不要图方便直接放到 List 里做批量分析,那是把内存往悬崖上推。

5.5 坑五:回调里读响应Body拿到的是空串

现象:BeforeResponse 里想提取响应里的某个字段,读 ResponseBody 结果是空。

原因:FiddlerCore 在 BeforeResponse 触发时,响应体并未保证完整读入内存。它是一个流式代理,Body 可能在事件触发时只读取了一部分。

解决:先调用 utilLoadResponse 确保完整加载:

private void OnBeforeResponse(Session oSession) { oSession.utilLoadResponse(); // 强制读取完整响应体 var body = Encoding.UTF8.GetString(oSession.ResponseBody); Debug.WriteLine(body); }

这一条在写响应拦截和 Mock 逻辑时几乎是必踩的坑。判断“要不要加 utilLoadResponse”有个简单标准:只要你在事件里访问 ResponseBody 且目标是拿内容做逻辑判断,就加;如果你只是想拿 responseCode 做统计,不需要加。

5.6 坑六:证书过期、卸载不干净导致二次启动报错

现象:程序升级重启后 FiddlerCore 启动失败,提示证书相关错误,或者新生成证书与旧证书不一致导致客户端校验失败。

原因:FiddlerCore 默认证书有有效期,过期后不会自动重新生成。旧版本生成的根证书没有清理,新版本检测到旧证书存在,不重新创建,但旧的私钥可能已经丢失或路径变化。

解决:启动前做一次证书状态检查和重建:

if (!FiddlerApplication.CertificateMaker.CheckForExistingRootCertificate()) { FiddlerApplication.CertificateMaker.CreateRootCertificate(); } else { // 证书已存在但不一定有效,按需判断是否重建 FiddlerApplication.CertificateMaker.RemoveCertificate(); FiddlerApplication.CertificateMaker.CreateRootCertificate(); }

我一般会在正式环境里把这个逻辑放到“证书目录可写”的前提下,并且每次启动时打印证书指纹,这样后续排查证书问题时能快速判断当前进程用的是哪张证书。证书相关的错误信息往往藏在异常堆栈最深处,拿到后先看是不是“certificate has expired”或“private key not found”,基本能定位是这类问题。

6. 进阶:把FiddlerCore从记录器改成拦截器,再盯到WebSocket

FiddlerCore 的记录能力很多人用过,但把它改造成一个带逻辑的拦截器,价值会高一个量级。最常见的做法是在 BeforeRequest 里按 URL 规则做请求改写或直接短路:

private void OnBeforeRequest(Session oSession) { if (oSession.fullUrl.Contains("/api/pay/")) { oSession.utilCreateResponseAndLoadBody("{\"code\":500,\"msg\":\"mock失败结果\"}"); oSession.responseCode = 200; oSession.oRequest.headers["Host"] = "mock.local"; // 标记来源 oSession.state = SessionStates.Done; // 不再转发到服务器 } }

这样就能在测试环境里把某个真实接口的响应替换成预设数据,比改数据库做测试数据快得多。拦截器的核心思路是:确认逻辑判断、构造响应、终止转发。三个动作缺一不可,尤其是最后把 oSession.state 改为 Done,否则请求还是会继续发到线上。

WebSocket 和 wss 流量是个容易忽视的增量点。FiddlerCore 对 WebSocket 支持不如 HTTP 那样透明,它的处理方式是在 BeforeRequest 阶段识别 Upgrade 头,然后透传后续帧。要做 WebSocket 消息级别的抓取,需要在 AfterSessionComplete 之后从会话里检查是否有 WebSocket 帧数据,再做解析。这个方法不够优雅,但能解决“wss 流量完全看不见”的问题。如果业务里 WebSocket 是核心路径,更稳的做法是让客户端把消息主动上报一份到调试接口,不要把 FiddlerCore 当作 WebSocket 协议的完整调试器,它在纯 WebSocket 场景下边界暴露得很快。

我自己的习惯是 FiddlerCore 只承担 HTTP/HTTPS 链路的录制、改写和状态统计这三件事,WebSocket 的细粒度调试交给业务侧日志埋点。最初做流量分析平台时,我把所有希望都压在 FiddlerCore 上,结果项目上线后被 WebSocket 和长连接的盲区拖了两周。后来把边界划清楚,每个工具只解决一段问题,FiddlerCore 负责 HTTP 请求响应的录制和回放,平台负责展示,复杂度一下就降下来了。希望这篇关于 FiddlerCore 抓包的拆解能帮你在接入前避开那些我踩过的坑,让你在调试工具上节省的时间,真正花在业务本身。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询