
最近排查一个某内部系统的登录超时问题后端日志显示请求已经到了但响应时间一直波动浏览器 F12 只能看到 Web 端的流量App 里真正传参的情况完全看不见。折腾到半夜最后是靠 Mitmweb 把完整的请求响应链捞出来才定位到是某个响应头被上游网关吃掉导致客户端一直重试。这件事让我意识到Mitmweb 的参数配置才是真正决定调试效率的东西。不少同学是直接敲mitmweb就开抓等遇到端口占用、证书不生效、脚本注入失败、流量文件打不开这些情况才开始一页页翻文档。这篇文章就围绕 Mitmweb 参数配置来写把我自己实际用下来最有价值的参数组合、常见坑和排查思路一次讲清楚。适合前后端开发、测试同学以及做接口联调或流量分析的同学参考不管你是第一次接触还是已经用过一段时间应该都能从中找到能直接抄走的命令行。1. 先把运行环境收拾利索安装版本与证书信任这两道坎1.1 安装方式与 Python 版本Mitmweb 是 mitmproxy 工具族里的 Web 界面版本安装走 Python 包管理最方便。我推荐在虚拟环境里安装避免污染系统里其他 Python 项目的依赖python3 -m venv .venv source .venv/bin/activate pip install mitmproxy安装完用版本号验证一下mitmweb --version如果能看到类似Mitmproxy: 10.x.x的输出说明装好了。这里的版本号很重要后面不少参数的行为在不同大版本之间会有差异。我自己就遇到过照着老教程写--set websockettrue结果新版直接不识别的情况。提示不建议用sudo pip install全局安装很容易把系统 Python 环境搞乱。虚拟环境是成本最低的隔离方案。1.2 证书信任为什么 HTTPS 流量全是乱码第一次启动 Mitmweb 后抓取 HTTPS 请求会发现流量列表里都是解密失败或连接错误这不是工具坏了而是它作为中间层需要被客户端信任。Mitmweb 首次运行会在用户目录生成一套本地 CA 证书路径大概是~/.mitmproxy/mitmproxy-ca.pem。要把这套证书装到测试设备上最省事的办法是直接用 Web 控制台自带的证书下载页。电脑本机调试访问http://127.0.0.1:8081/cert/pem下载证书双击导入系统信任区。手机真机调试手机连上同一局域网后访问http://电脑IP:8081/cert/按设备类型下载安装。Android 7 及以上版本很多应用默认不信任用户 CA 证书即使你安装了也仍然抓不到需要在应用的networkSecurityConfig里显式允许用户 CA或者用调试包。iOS 设备安装描述文件后还要去“关于本机 证书信任设置”里打开完全信任开关否则 Safari 会报证书错误。这一步经常被忽略导致很多人误以为工具不支持 HTTPS。实际上只要证书信任了剩下的参数配置才有意义。1.3 用一个最小命令验证环境证书弄完先别急着上复杂参数跑一个最小命令确认环境正常mitmweb --listen-port 8899 --web-port 8081启动后浏览器打开http://127.0.0.1:8081能看到消息列表和漏斗过滤栏。这时候随便访问一个 HTTP 页面消息列表里应该出现对应记录。能走到这一步说明安装、端口、Web 控制台三个环节都通了再往下加参数就不会互相甩锅。2. 上手第一个参数组合流量入口和控制台端口是两个独立维度2.1 端口参数各自管什么Mitmweb 启动后虚线监听的是两个端口很多人把它们混为一谈导致怎么调都不对。这里我建议先记住--listen-port管的是流量入口客户端要把流量转发到这个端口--web-port管的是调试界面浏览器通过这个端口看抓包结果。参数默认值作用--listen-host127.0.0.1流量入口绑定的地址--listen-port8080客户端流量转发过来的端口--web-host127.0.0.1Web 控制台绑定的地址--web-port8081浏览器访问控制台的端口默认情况下mitmweb会把流量入口和控制台都绑在127.0.0.1也就是只允许本机访问。这个设计是安全的但坑也在这手机真机调试时如果你只改端口不改成0.0.0.0手机根本连不上你的电脑。2.2 最常见的本地真机抓包组合我自己最常用的基础组合是mitmweb --listen-host 0.0.0.0 --listen-port 8899 --web-port 8081拆开来看--listen-host 0.0.0.0表示流量入口监听所有网卡这样同一局域网内的手机才能把流量指过来。--listen-port 8899是手机端要填的端口我不用默认 8080 是因为开发机上这个端口被各种服务占用的概率太高。--web-port 8081保持默认方便记忆。手机端在 Wi-Fi 设置里把“HTTP 转发”或“手动配置”指向电脑的局域网 IP 和 8899 端口然后浏览器打开http://电脑IP:8081就能看到手机流量实时出现。注意这时候 Web 控制台绑定了127.0.0.1所以只有电脑本机能访问手机访问不到也没关系这反而是更安全的配置。2.3 端口占用与防火墙排查如果启动时提示Address already in use说明端口已经被别的进程占用了。排查命令lsof -i :8899 netstat -tlnp | grep 8899找到占用进程后要么换端口要么先处理掉旧进程。还有一个容易被忽略的点是系统防火墙本机抓包通常不受影响但手机真机抓包时如果电脑开启了防火墙即使监听地址是0.0.0.0外部连接也可能被拦掉。需要放行对应端口或者把电脑加入同一个无隔离网络。注意公司办公网络里可能还有更严格的网络准入策略真机抓包前先确认这类限制否则定位半天也连不上。3. 从“只开眼”到“能干活”脚本注入、运行期选项与流量落盘3.1--scripts参数给请求和响应打补丁抓包只能看数据改数据要靠脚本注入。Mitmweb 支持用 Python 脚本拦截和修改请求响应这在调试接口异常时特别有用。举个我实际写过的例子# addon.py from mitmproxy import http def request(flow: http.HTTPFlow) - None: if login in flow.request.pretty_url: flow.request.headers[X-Debug-Mode] 1 def response(flow: http.HTTPFlow) - None: if login in flow.request.pretty_url: flow.response.headers[X-Backend-Latency] str( flow.response.timestamp_end - flow.response.timestamp_start ) print(flow.request.pretty_url, flow.response.status_code)启动时带上mitmweb --listen-port 8899 --web-port 8081 --scripts addon.py这段脚本做的事情是请求到达时给登录接口加一个调试头响应返回时把后端处理耗时写进自定义响应头。配合 Web 控制台直接能看到不用再翻后端日志去算耗时。脚本里的事件函数名是约定好的request和response分别对应每个请求和响应的回调比在控制台里一条条改更高效。3.2--set参数运行时选项才是进阶的关键--set参数负责修改工具运行时的内部配置相当于把 Web 界面“选项”页里的开关直接写成命令行。我常用的几个选项如下选项作用适用场景block_globalfalse允许转发到外部地址的请求浏览器访问公网接口时默认会被拦截stream_large_bodies1m超过 1MB 的响应体按流式处理不整体缓存在内存里抓取大文件下载、视频流接口ssl_insecuretrue忽略上游证书校验错误本地测试自签名证书的后端服务connection_strategylazy延迟建立到目标服务器的连接流量很大时减少无谓的连接开销http2false关闭 HTTP/2 支持重放请求时部分服务端对 HTTP/2 兼容不佳举个例子默认情况下浏览器访问外部 HTTPS 网站时Mitmweb 会因为安全策略拦截请求很多新手第一次抓包发现列表里什么都没有就是这个问题。排查时可以记住消息列表里出现400或502同时日志提示block_global就直接在启动命令里加--set block_globalfalse。3.3 把流量保存下来-w/--save-stream-file调试接口最怕“刚才明明抓到了但忘了留证据”。-w参数可以把在线流量实时写入一个文件mitmweb --listen-port 8899 --web-port 8081 -w trace_$(date %Y%m%d).mitm这样生成的.mitm文件包含请求、响应、证书信息、时间戳等完整上下文比浏览器导出的 HAR 信息更全。我通常在开始抓包前就把-w带上哪怕用不上事后也能回溯。3.4 离线查看流量--read-file如果已经有一份.mitm文件不需要重新抓包就能用 Web 控制台分析mitmweb --read-file trace_20250101.mitm --web-port 8082这个模式非常有用别人发你一份流量文件你直接起一个离线 Web 控制台慢慢看不会干扰正在运行的服务。因为不会启动新的流量入口所以只需要指定 Web 端口即可。对比一下在线模式是“边抓边看”离线模式是“抓完再看”后者遇到复杂问题可以慢慢分析不用逼着用户一直开着电脑。4. 几个高频工作流的参数组合真机抓包、后端联调、离线分析4.1 真机 App 抓包的标准起手式真机抓包需要把流量入口暴露到局域网同时又要考虑外部地址访问和文件保存我的标准命令是这样mitmweb \ --listen-host 0.0.0.0 \ --listen-port 8899 \ --web-port 8081 \ --set block_globalfalse \ --set stream_large_bodies1m \ -w trace_$(date %Y%m%d_%H%M).mitm四个关键点第一--listen-host 0.0.0.0让手机能连入第二block_globalfalse避免访问公网接口时被拦截第三stream_large_bodies1m避免图片或视频接口把内存撑爆第四-w实时落盘。这套组合覆盖了我 90% 的移动端排查场景跑起来之后手机正常操作十分钟基本想要的数据都能抓到。有一个容易忽略的细节手机屏幕熄灭后Wi-Fi 可能进入省电休眠导致流量中断。抓包时建议在手机开发者选项里开启“不锁定屏幕”或者至少保持屏幕常亮。4.2 后端联调时如何只关注特定接口抓包数据一大就难定位尤其后端联调时前端页面会同时产生几十个静态资源请求。Mitmweb 的 Web 控制台左上角有过滤栏支持~u、~q、~s等过滤表达式。比如只留下 URL 中包含api的请求~u /api/只留下响应状态码是 500 的请求~s 500把两个条件组合在一起~u /api/ ~s 500过滤只是控制台显示层面的事不会影响抓包内容。如果确实想彻底忽略某些域名可以在启动时用--ignore-hosts参数例如mitmweb --ignore-hosts my-internal.test被忽略的地址不会出现在列表里能大幅减少噪音。我用下来感觉过滤栏更灵活因为不需要重启就能改条件适合调试过程中不断调整关注范围。4.3 一次真实的超时问题定位过程这里用一个虚构但很典型的例子说明参数组合怎么发挥作用。某天同事反馈一个登录接口偶发超时我按上面真机命令起好环境手机把流量指到 8899十几分钟后就抓到了失败请求。看响应耗时发现接近 10 秒正常应该 200 毫秒。进一步用脚本注入把X-Backend-Latency写进响应头很快就确认耗时发生在后端应用层而不是网络链路。继续看请求头发现客户端带了一个过大的Cookie后端在处理时触发了某个校验逻辑白等了 8 秒多。问题根因就这样通过流量链路上的耗时标记定位出来全程没有改过一行后端代码。这类问题如果只靠日志往往只能看到两端时间戳中间环节的耗时完全是黑的。Mitmweb 的脚本注入能力相当于在链路上打点配合-w保存的原始流量排查后还能整理成一份带证据的报告。4.4 离线文件的分发与协作.mitm文件体积通常很小传给别人很方便。同事拿到文件后执行mitmweb --read-file trace_20250101.mitm --web-port 8083就能在浏览器里看到和我当时完全一样的界面包括每个请求的时间顺序、响应状态、Header、Body不需要重新抓包。这种离线协作方式在很多排查场景里比截图和日志更靠谱因为所有原始信息都在观看者可以自己去验证。5. 那些翻文档才发现的坑重放失败、大文件处理与生产规范5.1 重放请求怎么总是不成功Web 控制台里每条流量右键都可以重放看起来很简单但我在实际使用中经常被它坑到。最典型的失败原因是接口依赖动态签名重放时请求头里的时间戳和 token 已经过期服务端自然拒绝。这种问题跟 Mitmweb 参数无关而是需要配合脚本在重放前更新请求头。第二个坑是 HTTP/2 连接复用。有些服务端对同一连接上的重放请求处理得不好表现为第一次重放成功第二次开始失败。这时可以在启动参数里加--set http2false强制走 HTTP/1.1 重放成功率会高很多。第三个坑是重放只重发请求不会重新建立完整的 TLS 会话上下文。如果服务端对会话状态敏感重放请求可能被判定为异常。我的经验是重放适合验证“同样的请求是否会得到同样的响应”不适合直接当作压测工具更不要把重放结果当作线上问题已经修复的证据。5.2 大文件与长连接会让内存暴涨在线抓包默认会把响应体完整读进内存如果调试的是视频流或大文件下载接口机器内存会肉眼可见地涨上去。处理办法就是前面提到的mitmweb --set stream_large_bodies1m这个参数的意思是超过 1MB 的响应体不再整体缓存而是边收边转发。代价是 Web 控制台里看不到完整的消息体但状态码和耗时信息仍然保留。对大文件接口我最关心的是耗时和状态消息体爱看不看。所以这个取舍很划算。长连接超时同样值得注意。某些接口会长时间挂着如果客户端和 Mitmweb 之间有一方主动断开流量列表里会看到一个连接异常。这时候可以配合脚本记录连接事件或者检查--set stream_large_bodies设置后是否改变了连接生命周期。这类问题定位起来比较费劲建议一开始就定好哪些接口需要流式处理。5.3 安全和规范不要在生产环境抓包Mitmweb 的--listen-host 0.0.0.0组合很实用但也意味着同一局域网内任何设备都能把流量指向你。安全习惯上我给自己定了几个规矩默认只绑127.0.0.1只有真机调试时才临时用0.0.0.0用完立刻退出。抓到的流量文件不要随手放在共享目录里面很可能有登录态 Cookie、Token 等敏感信息。.mitm文件传给别人时优先用支持加密的通道。不在生产环境直接部署 Mitmweb即使是只读分析也要先用导出的文件在本地处理。这些规矩不是教条而是我确实见过有人为了图方便把监听端口暴露在办公网里结果被抓到了大量业务敏感信息。调试工具的便利性必须放在可控范围内。5.4 把常用参数封装成启动脚本命令行参数记太多容易乱我建议把常用组合写成脚本团队里也能统一使用。一个最小化的封装示例#!/usr/bin/env bash # start_capture.sh PORT${1:-8899} SAVE_FILE${2:-trace_$(date %Y%m%d_%H%M).mitm} mitmweb \ --listen-host 0.0.0.0 \ --listen-port $PORT \ --web-port 8081 \ --set block_globalfalse \ --set stream_large_bodies1m \ -w $SAVE_FILE用的时候chmod x start_capture.sh ./start_capture.sh 8899脚本化之后还有一个好处不同项目之间可以共用同一套参数基线新同事上手时不用再去翻一长串文档。我自己会把脚本放在项目的scripts/目录下和代码一起维护。参数变更会有版本记录方便回溯是哪次改动导致抓包行为变化。最后再分享两个小技巧第一先想清楚这次抓包的目标再决定参数。只抓本机 Web 接口不需要--listen-host 0.0.0.0只分析已有文件用--read-file就够了要改请求就加--scripts。需求越明确命令越简单排错越容易。第二可以把最常用的参数做成 shell alias省去每次敲一大串alias mwebmitmweb --listen-port 8899 --web-port 8081 --set block_globalfalse -w trace_$(date %Y%m%d).mitm我在实际使用中最大的体会是Mitmweb 的参数本身并不复杂复杂的是怎么根据场景选对参数以及遇到 HTTPS 证书、重放失败、大文件内存暴涨这些具体问题时能快速定位到对应开关。把这些参数组合背下来调试接口的效率真的能翻倍。