
一个请求发出去,返回 502。这句话里没有任何可用信息。你要知道的不是「失败了」,是失败发生在哪一跳。
四个工具都能看这个请求,但它们站的位置不一样:curl 站在客户端里面,HTTPie 站在人的手边,mitmproxy 站在两者中间,Wireshark 站在网线上。位置决定了你能看到什么,也决定了你看不到什么。
边界不是能力,是谁在链路上
这四个工具经常被放在一起比功能,其实它们的分歧不在功能多少,在介入方式。curl 自己造请求,mitmproxy 拦别人的请求,Wireshark 只看得到经过网卡的东西。
| 维度 | curl | HTTPie | mitmproxy | Wireshark |
|---|---|---|---|---|
| 看到的内容 | 自己发出的那一个请求 | 自己发出的那一个请求 | 链路上所有 HTTP 会话 | 链路上所有数据包 |
| 能否改包 | 重发一次即可 | 重发一次即可 | 可实时改写,不改客户端 | 不可改,只能看 |
| TLS 明文 | 自己发起,天然明文 | 自己发起,天然明文 | 需装 CA 证书 | 需密钥日志,否则只有密文 |
| 是否要动客户端 | 不用 | 不用 | 要设代理与证书 | 不用 |
| 可脚本化 | 强,退出码与 -w 模板 | 中 | 强,Python 插件 | 中,tshark 可脚本 |
| 典型误用 | 当压测工具 | 当团队规范 | 当生产环境审计 | 当 HTTP 调试器 |
表格里最容易被忽略的是第四行。mitmproxy 是唯一一个要求你改客户端配置的工具,这个代价换来的能力是「不改代码也能改请求」。
1. curl:当你只想要一句答案
绝大多数排障问题的答案,一条 curl 就够了。响应头、状态码、重定向链路、TLS 握手版本、耗时分布,它都能单独打出来。它的问题不是能力不足,是默认输出太省。
curl -sS -o /dev/null -D - \
-w 'dns:%{time_namelookup} conn:%{time_connect} tls:%{time_appconnect} ttfb:%{time_starttransfer} total:%{time_total}\n' \
https://api.example.com/health
这一条能回答「慢在哪」:DNS 慢、建连慢、TLS 慢、还是服务端算得慢。ttfb 与 total 之间的差值是传输时间,ttfb 之前的每一段都有独立计时,这是浏览器网络面板也给不了的粒度。
它的边界在于:只能发你自己构造的请求。客户端发出去的东西和你手写的不一样时,curl 帮不了你——这也是后面两个工具存在的理由。
2. HTTPie:当请求要被人读
HTTPie 的差异只有一处,但这一处很实在:语法按「方法 地址 头 体」的顺序平铺,冒号即赋值。它优化的是输入和阅读,不是能力。
http POST https://api.example.com/v1/orders \
Authorization:'Bearer eyJ...' \
Content-Type:application/json \
items:='[{"sku":"A-1","qty":2}]'
把它放进代码仓库是它真正的用途。一个 .http 文件配一份环境变量,新人拉下来就能跑通接口,不需要读三段 curl 转义。它的价值在团队协作,不在单人排障。
边界也很清楚:不适合写进脚本做批量调用。它的输出是给人看的彩色结构,解析它比解析 curl 的输出更费劲。
3. mitmproxy:当你必须改一个字节
前两个工具都在客户端这边,mitmproxy 在中间。它伪装成代理,用自签 CA 解开 TLS,看清文,再重新加密发给服务端。这是唯一能在不改客户端代码的前提下,看见并修改真实流量的方式。
代价也很明确:客户端必须信任那个 CA。手机上装证书这一步,iOS 还要额外去「关于本机 – 证书信任设置」里手动打开开关,漏了这一步的现象是所有请求都失败,而不是只失败一部分。
# 只拦需要的域名,其余直通,避免把系统更新也解一遍
mitmproxy --mode regular@8080 \
--ignore-hosts '^(?!.*api\.example\.com).*$' \
--set confdir=~/.mitmproxy
它最实用的场景不是看,是复现。把一个偶发的 401 抓下来,改成正确的时间戳重放,看服务端到底在比什么。能改,才能把「偶发」变成「必现」。
边界:它按会话工作,不适合高并发与长时间挂载,也不该出现在生产入口。它的内存随会话数上涨,跑一天不重启,几百兆是常态。
4. Wireshark:当问题在 HTTP 之下
Wireshark 看的是包,不是请求。这个区别在 TLS 普及之后变得决定性:一个 HTTPS 请求在它眼里是十几条 TCP 段加一串 Encrypted Application Data。没有密钥日志,你连 URL 都看不到。
所以它的正确用途是回答 HTTP 层看不到的问题:三次握手有没有完成、有没有 RST、MTU 是不是被中间设备挡了、重传率多少、窗口是不是被打到零。这些症状在应用层表现成「偶发超时」,在包这一层是可以数出来的。
# 在服务器上抓,别开 GUI
tcpdump -i eth0 -s 0 -w /tmp/edge.pcap 'tcp port 443' -c 20000
# 回到本地分析
tshark -r edge.pcap -q -z io,stat,1,'tcp.analysis.retransmission'
这一条输出的是每秒重传数。如果它在某个时间点持续非零,问题就不在后端代码里,在链路上。
边界:它不解释业务。看到一堆包不等于看懂了一个请求。把它当 HTTP 调试器用,是这四个工具里最常见的一种错配。
三套组合
工具之间不是替代关系,是接力关系。下面三套是按场景配的,不是按偏好配的。配错的成本通常不是白装,是排查方向从一开始就偏了。
- 接口契约验证:一个 .http 文件(HTTPie 格式)+ curl 做 CI 里的冒烟检查。前者给人读,后者给流水线跑,两边共用同一份地址与环境变量。
- 移动端联调:mitmproxy 拦真机流量 + 脚本自动改写某个字段。适合「客户端改一版要发测试包」的场景,改包比发版快一个数量级。
- 线上说不清在哪慢:tcpdump 抓 30 秒 pcap + tshark 看重传 + curl 的 -w 分阶段计时。三者对齐到同一个时间窗口,才能判断是链路还是应用。
第二套里有一个常被跳过的细节:mitmproxy 的脚本要写成幂等。它在每个请求上都会执行一次,任何带状态的写法都会在第三个请求开始出问题。
四种选错的信号
下面四条不是理论,是四个具体的行为特征。出现任何一条,说明工具和问题不匹配。换工具比在原工具上硬想办法便宜。
- 你打开 Wireshark 想找 JSON 字段,只看到 Encrypted Application Data。你需要的不是抓包,是代理。
- 你在自己电脑上用 mitmproxy 抓 curl 的请求。curl -v 一行就够,还不用处理证书。
- 你把 curl 放进 for 循环当压测。它是串行客户端,测出来的是你的脚本速度。
- 你在生产机上开 Wireshark 图形界面。应该 tcpdump 落盘,拉回本地再分析。
第一条尤其值得记。TLS 之后,「抓包看内容」这件事在多数场景已经不成立,能看内容的只有两种:你自己发的,和你装了证书的。工具没变弱,是链路变暗了。
写在最后
这四个工具的学习成本差得很远:curl 半小时,HTTPie 十分钟,mitmproxy 半天,Wireshark 按年算。但决定用哪个的从来不是学习成本,是问题在哪一层。
大部分人的习惯是先装最重的那个,然后所有问题都用它解。工具越强,越容易让人跳过「先判断问题在哪一层」这一步。
真正省时间的顺序是反过来的:先用 curl 拿到一句话的答案,拿不到再往中间加一层代理,还拿不到才去抓包。每往下一层,成本翻倍,能回答的问题却更窄。
你上一次为了看清一个请求,最后是在哪一层找到答案的?

评论 (0)