用Fiddler模拟弱网:从原理到实操的完整指南 你可能也遇到过这种情况功能测试全部通过、联调也一切正常结果产品一上线就收到用户反馈“在电梯里页面打不开”“在地下室请求一直转圈”“明明网络信号显示满格App却像断网一样”。这些问题的共性是常规网络环境下根本复现不出来只有网络质量变差时才暴露。团队里越来越多的人开始把弱网测试列为必做项而 Fiddler 作为日常最常用的 HTTP 抓包调试工具除了抓接口、断点改包、模拟请求之外其实也能承担弱网模拟的活。这篇文章就从原理到实操把用 Fiddler 做弱网测试这件事讲透适合刚接触弱网测试的测试工程师、需要自测弱网场景的客户端开发以及想给服务端接口做容错验证的后端同学。1. 弱网测试到底需要测什么先想清楚再动手1.1 弱网不是“信号差”这么简单很多刚接触弱网测试的同学第一反应是“把网速调慢一点然后看看接口会不会挂”。这个理解不能说错但太粗糙了。真实世界里的“弱网”其实是四种问题同时作用后的结果带宽低、延迟高、丢包多、抖动大。这四个维度带来的表现完全不一样。带宽低的时候大图片、视频流、批量接口数据都传得慢App 容易出现加载超时、图片占位、列表数据出不来延迟高的时候接口本身数据量很小但一个请求发出后迟迟等不到响应用户感觉“卡住”了丢包率一旦上去了TCP 层会不断重传重传又加剧延迟严重时连接直接断开抖动则表现为网络忽快忽慢时延曲线像心电图一样起伏视频播放卡顿、音画不同步基本都是抖动造成的。所以弱网测试并不只是“把网络变差”而是要提前验证应用在这些劣化条件下的行为接口超时时间设置是否合理、loading 状态有没有反馈、请求失败后会不会重复提交、弱网下图片是否走了缩略图或懒加载、缓存有没有兜底、用户能不能看到错误提示并重试。这些才是弱网测试真正要回答的业务问题。纯粹把网速调慢然后拍脑袋说“是慢了点”起不到质量保障的作用。1.2 为什么选择 Fiddler 做弱网模拟市面上做弱网模拟的方案不少但对比下来Fiddler 是综合成本最低、可控性最高的选择。真机弱网环境比如去地铁、地下车库实测优点是完全真实缺点是场景不可控、复现困难、没法量化而且一次只能验证当前环境的现状想测多种网络档位就得反复跑不同地方。浏览器自带弱网功能DevTools 里的网络模拟只能作用于浏览器测不了手机 App对于移动端项目基本派不上用场。独立弱网工具有些系统自带网络限制工具功能确实直观但只支持特定系统而且一般只能在电脑上生效没法给手机 App 做代理。商业抓包工具同类工具里也有类似能力脚本扩展性也不错但需要授权费用团队采购流程也麻烦。Fiddler 的优势在于免费、跨平台、支持手机代理、FiddlerScript 脚本引擎足够灵活可以针对域名、路径、请求类型做精细化限速。它不是功能最强的弱网工具但它是绝大多数测试团队和开发自测最容易落地的那一个。能用最小的成本覆盖大部分弱网测试场景这是选择它的核心理由。2. 动手前必读Fiddler 模拟弱网的底层原理2.1 请求和响应在 Fiddler 里的流动路径要理解弱网模拟的原理先要知道 Fiddler 在链路上扮演的角色。Fiddler 本质上是一个 HTTP 代理手机或者浏览器发请求时流量不是直接到达服务器而是先把请求发给 Fiddler由 Fiddler 转发给服务器服务器返回的响应也是先回到 Fiddler再由 Fiddler 交给客户端。也就是说所有 HTTP/HTTPS 流量都会在这个中转站经过。FiddlerScript 是 Fiddler 内置的脚本引擎它暴露了两个关键事件OnBeforeRequest 和 OnBeforeResponse。前一个在请求被转发到服务器之前触发后一个在响应被返回到客户端之前触发。弱网模拟的核心操作就是在这两个事件的回调里插入人为的延迟。在 OnBeforeRequest 里做手脚影响的是上行流量在 OnBeforeResponse 里做手脚影响的是下行流量。理解了这条流动路径就理解了 Fiddler 能模拟什么、不能模拟什么。2.2 trickle-delay 参数到底是什么意思很多教程会直接让你在脚本里填 300 或者 150但没人告诉你这两个数字代表什么。这个参数的设计很有意思它不是“固定延迟多久”而是“每 KB 数据需要延迟多少毫秒”。oSession[request-trickle-delay] 控制的是请求上行时的每 KB 延迟时间单位是毫秒/KBoSession[response-trickle-delay] 控制的是响应下行时的每 KB 延迟时间单位同样是毫秒/KB。打个比方把网络通道想象成一条水管。固定延迟是“打开阀门之前先等 2 秒”而 trickle-delay 是“把水管换成了细管子”不管水流多少单位时间只允许这么多水通过。所以它模拟的是带宽限制不是单纯的网络延迟。一个 10KB 的请求如果每 KB 延迟 125 毫秒总的上传耗时就会增加 1.25 秒一个 800KB 的响应如果每 KB 延迟 30 毫秒下载耗时就会增加 24 秒。数据量越大延迟越长这正是窄带网络的特征。如果只设置了 trickle-delay模拟的是一种“带宽极窄但交互顺畅”的网络真实弱网往往还伴随高延迟和丢包。所以完整的弱网模拟需要把 trickle-delay 跟固定延迟组合使用才能更接近真实环境。2.3 Fiddler 内置的 Simulate Modem Speed 做了什么Fiddler 的菜单里其实有一个现成的慢速选项Rules - Performance - Simulate Modem Speed。很多人以为勾选它就能做弱网测试但你可能不知道它背后到底做了什么。它的原理就是给 request-trickle-delay 设置了 300给 response-trickle-delay 设置了 150。算一下就知道上行每 KB 延迟 300ms 相当于约 26kbps 的带宽下行每 KB 延迟 150ms 相当于约 53kbps 的带宽差不多是早年 56K 拨号上网的水平。这个内置选项胜在快速一键开启但它有两个问题第一参数是写死的没法精确模拟你想要的某个带宽档位第二它不区分请求所有流量一律限速容易把问题面扩大。所以内置选项适合功能冒烟时快速看一眼真正做弱网测试还是得自己写脚本。3. 核心实操从 0 到 1 在 Fiddler 里做弱网模拟3.1 三步快速准备代理、证书、环境在写脚本之前先把 Fiddler 的代理环境搭好。否则脚本写完手机流量根本没走 Fiddler等于白忙。第一步电脑端 Fiddler 开启远程连接。打开 Tools - Options - Connections勾选 Allow remote computers to connect确认监听端口是 8888。如果不勾这个手机没法把请求代理到电脑上。第二步配置手机代理。让手机和电脑连接同一个局域网进入手机的 WiFi 设置把代理改成手动服务器地址填电脑的局域网 IP端口填 8888。这里有个容易踩坑的点电脑如果同时连着无线和有线网要确认填的是手机能访问到的那个网卡 IP。填完之后可以用手机浏览器访问一个网页如果能打开说明流量已经走了 Fiddler。第三步处理 HTTPS。弱网测试如果只测 HTTP 接口还好现在的 App 基本都是 HTTPS所以必须开启 Fiddler 的 HTTPS 解密功能。在 Tools - Options - HTTPS 里勾选 Decrypt HTTPS traffic然后用手机浏览器访问 http://代理IP:8888下载并安装 Fiddler 的根证书。这里要注意Android 7 及以上系统默认不信任用户安装的证书如果 App 本身没有做相关配置直接抓包会看到大量 CONNECT 隧道和无法解密的密文。这种情况下需要让开发配合调整网络安全配置或者用支持系统证书安装的测试环境来验证这是个常见坑提前知道能省很多时间。3.2 编写第一版弱网脚本环境就绪后打开 FiddlerScript 编辑器。在 Fiddler 菜单栏找到 FiddlerScript 标签页或者直接用快捷键 CtrlR就会打开一个 CustomRules.js 文件。所有弱网规则都写在这个文件里。我的习惯是在脚本开头定义一个开关变量方便后续随时开启和关闭弱网规则不用每次改代码。public static var m_SimulateWeakNetwork true; static function OnBeforeRequest(oSession: Session) { if (m_SimulateWeakNetwork) { oSession[request-trickle-delay] 125; } } static function OnBeforeResponse(oSession: Session) { if (m_SimulateWeakNetwork) { oSession[response-trickle-delay] 30; } }写完保存Fiddler 会自动编译并重新加载脚本。如果语法有错误保存时会弹窗提示这时候脚本不会生效需要先修复错误。验证是否生效的方法很简单重新请求一个页面在 Fiddler 里选中对应请求打开右侧的 Statistics 面板对比开启弱网前后的耗时差异。如果响应 100KB、设置了 response-trickle-delay 为 30理论上会比正常网络多出约 3 秒的传输时间这个数字很容易观察到。3.3 如何按目标网络参数计算脚本里的数值trickle-delay 的数值不是拍脑袋定的它是可以计算的。公式很简单每 KB 延迟毫秒数约等于 1000 除以目标带宽对应的每秒 KB 数。举个例子目标上行带宽是 64kbps。64kbps 换算成 KB 每秒就是 64/8 8KB/s。那么每 KB 耗时就是 1000/8 125 毫秒。所以 request-trickle-delay 填 125就能把上行带宽压到大约 64kbps。同理目标下行带宽是 256kbps256/8 32KB/s每 KB 耗时 1000/32 ≈ 31 毫秒response-trickle-delay 填 31 或者 30 都行。需要额外模拟高延迟时可以在 OnBeforeRequest 里加入固定延迟static function OnBeforeRequest(oSession: Session) { if (m_SimulateWeakNetwork) { oSession[request-trickle-delay] 125; } if (oSession.HostnameIs(api.example.com) m_SimulateWeakNetwork) { System.Threading.Thread.Sleep(2000); } }Thread.Sleep(2000) 表示这个请求在发往服务器之前会强制卡住 2 秒。这模拟的是高延迟链路和窄带宽是两种不同的弱网表现。但是要特别注意Thread.Sleep 会占用 Fiddler 的会话处理线程如果同时有很多请求并发会把线程池耗尽导致所有请求都变慢。所以固定延迟适合小范围手动测试不适合大规模并发压测。3.4 一套贴近真实弱网的组合脚本实际测试时我一般会把限速和固定延迟组合起来按照想要的网络档位做一个完整的脚本。比如模拟一条“上行受限、下行一般、延迟偏高”的网络public static var m_SimulateWeakNetwork true; static function OnBeforeRequest(oSession: Session) { if (m_SimulateWeakNetwork) { oSession[request-trickle-delay] 125; if (oSession.HostnameIs(api.example.com)) { System.Threading.Thread.Sleep(1500); } } } static function OnBeforeResponse(oSession: Session) { if (m_SimulateWeakNetwork) { oSession[response-trickle-delay] 30; } }这里的 125 和 30 分别代表上行约 64kbps、下行约 256kbps1.5 秒的 Sleep 模拟额外链路延迟。不同项目对弱网的定义不一样没有一套参数能通吃所有场景关键是理解每个参数的含义然后按目标网络自己去算。4. 脚本之外的细节让弱网模拟更接近真实4.1 只针对特定域名做弱网规则很多初学的同学会把整个脚本做成“全局限速”结果一开弱网Fiddler 自己加载本地静态资源都慢界面卡到没法操作。而且全局限速会让页面里所有请求一起变慢根本无法定位是哪个接口拖垮了页面。更高效的做法是只对目标域名限速。比如要测电商 App 的商品详情接口就给商品详情相关的 API 域名加弱网其他资源如日志上报、统计请求保持正常。public static var m_SimulateWeakNetwork true; static function OnBeforeRequest(oSession: Session) { if (m_SimulateWeakNetwork oSession.HostnameIs(api.example.com)) { oSession[request-trickle-delay] 125; } } static function OnBeforeResponse(oSession: Session) { if (m_SimulateWeakNetwork oSession.HostnameIs(api.example.com)) { oSession[response-trickle-delay] 30; } }如果想针对一批域名生效可以用 HostnameIs 拼接多个条件或者用 URLContains 按路径匹配。这样做的核心价值在于能把弱网影响范围收敛到被测对象上测试结论更干净定位问题也更精准。4.2 带宽之外如何模拟丢包和抖动Fiddler 在 HTTP 代理层做弱网模拟有一个先天短板它模拟不了真正的丢包和网络抖动。原理很好理解Fiddler 接管的是应用层的 HTTP 请求而丢包发生在更底层的 TCP/IP 传输过程。Fiddler 可以延迟报文、限制速率但没法让底层网络栈真的丢掉一个数据包也没法制造忽快忽慢的时延抖动。如果项目的弱网测试要求覆盖丢包和抖动场景我的做法是用 Fiddler 配合专门的网络损伤工具来使用。Fiddler 负责带宽限制和固定延迟另一个网络模拟工具负责丢包和抖动两者配合起来基本能覆盖真实弱网的大部分表现。操作上可以先在 Fiddler 里开启针对目标域名的限速再在网络损伤工具里设置丢包率比如 5% 或 10%开启抖动几十到几百毫秒然后去跑业务场景。这套组合方案的成本很低效果却很接近真实弱网。4.3 弱网测试中要重点观察的行为弱网环境搭好了接下来观察什么才是关键。有些团队把弱网测试做成了“调慢网络之后走一遍主流程”发现接口能返回就认为通过其实遗漏了很多真正的风险点。我建议在弱网测试时至少覆盖这几个维度接口响应时间有没有超出用户可接受范围App 在请求长时间不返回时loading 状态和错误提示是否合理请求失败后的重试逻辑是否会造成重复提交图片和视频资源在弱网下是否走了合理的加载策略缓存机制是否能在弱网下兜底避免页面完全不可用客户端与服务端的数据在弱网下是否会出现不一致。把这些维度列成一份测试检查清单每轮弱网测试对照着过一遍比漫无目的地“慢网点点点”有效得多。5. 踩坑记录做弱网测试时最容易翻车的几个点5.1 脚本改了不生效90% 是这三个原因弱网脚本写好后发现不生效这是新手遇到最多的问题。根据我的经验绝大多数情况下不是 Fiddler 坏了而是下面三个原因之一。第一个原因是脚本没有保存。FiddlerScript 编辑器是即时编译机制但前提是你先按了保存脚本才会重新加载。改了代码不保存等于白改。第二个原因是属性名写错了。必须是 oSession[request-trickle-delay] 和 oSession[response-trickle-delay]注意字符串里的连字符和大小写拼错一个字符脚本能编译通过但延迟根本不会生效。第三个原因是流量根本没走 Fiddler 代理。手机或者测试环境没有配置代理或者 Fiddler 没有开启远程连接脚本写得再对也没用。排查方式是先看 Fiddler 的抓包列表里有没有出现目标请求如果没有说明流量没进来。还有一个容易被忽略的问题FiddlerScript 文件里如果其他地方存在语法错误整个脚本加载会失败。有时你只改了自己的弱网函数但文件里之前留下了一个语法问题保存时 Fiddler 会直接报错并拒绝加载新脚本。5.2 延迟数值和体感对不上要怎么调有同学设置了 response-trickle-delay 为 30然后去请求一个 5KB 的接口发现“也没多慢啊”。这是对参数理解不到位导致的。trickle-delay 的单位是每 KB 延迟毫秒数不是固定总延迟。5KB 的接口每 KB 延迟 30ms总延迟才 150ms体感当然不明显。如果我想要的是“一个请求固定卡顿 3 秒”那就应该用 Thread.Sleep 加固定延迟而不是只调 trickle-delay。两者适合的场景不同数据量大的资源适合用 trickle-delay 模拟带宽数据量小的接口模拟“假死”状态适合用 Sleep。另外测试机的网络环境本身也会影响体感。电脑连着千兆宽带和连着手机热点Fiddler 所在机器的出口带宽完全不同弱网模拟是叠加在基础网络之上的所以建议做弱网测试时尽量统一测试机的基础网络环境否则每次测出来的数据可能都不太一样。5.3 弱网测试的定位思路从现象到根因最后分享一个我自己印象很深的排查案例。A 同学负责的某 App 在弱网测试时出现了“重复下单”的问题表面现象是用户点了支付按钮请求一直转圈等了很久之后页面提示下单失败但用户刷新后发现订单居然创建成功了而且创建了两次。排查时先在 Fiddler 里开启弱网规则复现问题。抓包发现点支付按钮后客户端发起创建订单请求由于弱网延迟请求长时间没有得到响应客户端的超时时间设置过短触发了一次自动重试。重试请求和原始请求都到达了服务端而服务端接口没有做幂等校验于是同一笔业务被处理了两次。再往深看客户端转账逻辑里 loading 状态也没有阻止重复点击用户可能在等待时多点了一次。这个问题的根因链条靠“把网调慢”是看不出来的必须结合抓包看请求序列、状态码和耗时再对照服务端日志才能定位。弱网测试的定位思路基本是固定的先复现问题再抓包看请求序列和耗时检查是否有重试、是否有并发冲突、超时设置是否合理然后查看服务端日志确认根因最后修复回归。这套思路在弱网问题的排查中屡试不爽。最后再分享一个我的个人习惯每次开始弱网测试之前我先保存一份正常网络下的基线数据比如某个核心页面的接口平均耗时、总耗时、失败率。然后开启弱网规则再跑一遍同样的流程把两份数据对比放在一起。只要偏差超出预期范围问题点很快就能暴露出来。这个习惯帮我发现过很多不起眼但严重影响体验的问题。弱网测试是性价比很高的投入越早暴露问题线上丢的体验分就越少。