土法炼钢兴趣小组的算法知识备份

【网络工程】HTTP 调试方法论:curl、DevTools 与 mitmproxy

文章导航

分类入口
network
标签入口
#http#debugging#curl#devtools#mitmproxy#performance

目录

线上的 HTTP 请求行为经常和本地测试不一致——响应头被代理改写、缓存层返回了过期内容、TLS 握手失败但浏览器只显示 ERR_CONNECTION_RESET。面对这些问题,靠猜是不行的,必须有系统化的调试方法和工具链。

HTTP 调试的核心原则是”分层隔离”:把请求链路拆成 DNS 解析、TCP 连接、TLS 握手、请求发送、服务端处理、响应传输六个阶段,逐段定位瓶颈。本文围绕三个核心工具——curl、Chrome DevTools、mitmproxy——构建完整的 HTTP 调试方法论。

一、curl:命令行 HTTP 调试的瑞士军刀

curl 是最基础也是最强大的 HTTP 调试工具。它不依赖浏览器、不走系统代理、不受缓存干扰,能精确控制请求的每一个细节。

1.1 基础调试:查看完整请求响应

# -v (verbose) 显示完整的请求/响应头和 TLS 握手信息
curl -v https://api.example.com/health

# 输出示例:
# * Trying 93.184.216.34:443...
# * Connected to api.example.com (93.184.216.34) port 443
# * ALPN: offers h2,http/1.1
# * TLSv1.3 (OUT), TLS handshake, Client hello (1):
# * TLSv1.3 (IN), TLS handshake, Server hello (2):
# * TLSv1.3 (IN), TLS handshake, Certificate (11):
# * TLSv1.3 (IN), TLS handshake, CERT verify (15):
# * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
# * ALPN: server accepted h2
# > GET /health HTTP/2
# > Host: api.example.com
# > User-Agent: curl/8.4.0
# > Accept: */*
# >
# < HTTP/2 200
# < content-type: application/json
# < cache-control: no-store
# < x-request-id: abc-123
# <
# {"status":"healthy"}

# -I 只获取响应头(HEAD 请求)
curl -I https://example.com

# -s 静默模式 + -o /dev/null 丢弃 body,只看头
curl -s -o /dev/null -D - https://example.com

1.2 请求定制:模拟各种客户端行为

# 指定 HTTP 方法
curl -X POST https://api.example.com/users \
    -H "Content-Type: application/json" \
    -d '{"name":"test","email":"test@example.com"}'

# 发送表单数据
curl -X POST https://example.com/login \
    -d "username=admin&password=secret"

# 上传文件
curl -X POST https://api.example.com/upload \
    -F "file=@/path/to/document.pdf" \
    -F "description=test upload"

# 指定自定义头
curl -H "Authorization: Bearer eyJ..." \
     -H "X-Request-ID: debug-001" \
     -H "Accept: application/json" \
     https://api.example.com/users/me

# 指定 Cookie
curl -b "session=abc123; lang=zh-CN" https://example.com

# 保存和发送 Cookie(模拟浏览器的 Cookie 行为)
curl -c cookies.txt https://example.com/login -d "user=admin&pass=secret"
curl -b cookies.txt https://example.com/dashboard

1.3 –trace:字节级协议分析

-v 的信息不够时,--trace 提供了最底层的调试能力:

# 输出完整的字节流(十六进制 + ASCII)
curl --trace trace.log https://example.com

# --trace-ascii 只看 ASCII 部分(更可读)
curl --trace-ascii - https://example.com 2>&1 | head -40

# 输出示例:
# == Info:   Trying 93.184.216.34:443...
# == Info: Connected to example.com (93.184.216.34) port 443
# => Send SSL data, 512 bytes (0x200)
# 0000: 16 03 01 01 fb 01 00 01 f7 03 03 ...
# <= Recv SSL data, 155 bytes (0x9b)
# ...
# => Send header, 78 bytes (0x4e)
# 0000: GET / HTTP/2
# 0014: Host: example.com
# 0027: User-Agent: curl/8.4.0
# 003f: Accept: */*
# <= Recv header, 13 bytes (0xd)
# 0000: HTTP/2 200

# --trace-time 添加时间戳(分析延迟)
curl --trace-ascii - --trace-time https://example.com 2>&1 | head -20
# 09:15:32.456789 == Info: Trying 93.184.216.34:443...
# 09:15:32.478123 == Info: Connected ...
# 09:15:32.534567 => Send SSL data ...

1.4 –resolve:绕过 DNS 的精确调试

线上排查时,经常需要把请求发到特定的后端 IP,绕过 DNS 和负载均衡:

# 将 api.example.com 强制解析到指定 IP
curl --resolve api.example.com:443:10.0.1.50 \
     https://api.example.com/health

# 同时指定多个域名
curl --resolve api.example.com:443:10.0.1.50 \
     --resolve cdn.example.com:443:10.0.2.100 \
     https://api.example.com/page

# 配合 --connect-to 重定向连接(不改变 Host 和 SNI)
curl --connect-to api.example.com:443:backend-01.internal:443 \
     https://api.example.com/health

# 实际用途:
# 1. 灰度发布时测试特定后端
# 2. CDN 回源问题排查,直连源站
# 3. DNS 切换前验证新服务器
# 4. 多数据中心环境验证特定节点

1.5 timing 模板:HTTP 性能分解

curl 的 -w 参数可以输出请求的每个阶段耗时,这是 HTTP 性能分析的基础:

# 创建 timing 模板文件
cat > curl-timing.txt << 'EOF'
    dns_lookup:  %{time_namelookup}s\n
   tcp_connect:  %{time_connect}s\n
   tls_handshake: %{time_appconnect}s\n
  time_redirect:  %{time_redirect}s\n
time_pretransfer:  %{time_pretransfer}s\n
  starttransfer:  %{time_starttransfer}s\n
     total_time:  %{time_total}s\n
  download_speed:  %{speed_download} bytes/s\n
     http_code:  %{http_code}\n
   remote_addr:  %{remote_ip}:%{remote_port}\n
    ssl_verify:  %{ssl_verify_result}\n
      num_redirects: %{num_redirects}\n
EOF

# 使用 timing 模板
curl -s -o /dev/null -w "@curl-timing.txt" https://example.com

# 输出示例:
#     dns_lookup:  0.004123s        ← DNS 解析耗时
#    tcp_connect:  0.025456s        ← TCP 三次握手完成
#    tls_handshake: 0.078912s       ← TLS 握手完成
#   time_redirect:  0.000000s      ← 重定向耗时
# time_pretransfer:  0.079034s     ← 准备发送请求
#   starttransfer:  0.156789s      ← 收到第一个字节(TTFB)
#      total_time:  0.234567s      ← 请求总耗时

# 计算各阶段耗时:
# DNS 解析:     time_namelookup                     = 4.1ms
# TCP 连接:     time_connect - time_namelookup       = 21.3ms
# TLS 握手:     time_appconnect - time_connect       = 53.5ms
# 服务端处理:   time_starttransfer - time_appconnect = 77.9ms
# 内容传输:     time_total - time_starttransfer      = 77.8ms
# 批量测试脚本 — 多次请求取统计值
#!/bin/bash
URL="${1:-https://example.com}"
N="${2:-10}"

echo "Testing $URL ($N requests)..."
echo "---"

for i in $(seq 1 $N); do
    curl -s -o /dev/null \
        -w "%{time_namelookup} %{time_connect} %{time_appconnect} %{time_starttransfer} %{time_total}" \
        "$URL"
    echo ""
done | awk '{
    dns+=$1; tcp+=$2; tls+=$3; ttfb+=$4; total+=$5; n++
} END {
    printf "Average over %d requests:\n", n
    printf "  DNS:   %.3fms\n", (dns/n)*1000
    printf "  TCP:   %.3fms\n", ((tcp-dns)/n)*1000
    printf "  TLS:   %.3fms\n", ((tls-tcp)/n)*1000
    printf "  TTFB:  %.3fms\n", ((ttfb-tls)/n)*1000
    printf "  Total: %.3fms\n", (total/n)*1000
}'

1.6 TLS 调试

# 查看服务端证书链
curl -v --head https://example.com 2>&1 | grep -A 20 "Server certificate"

# 指定 TLS 版本
curl --tlsv1.2 --tls-max 1.2 https://example.com  # 强制 TLS 1.2
curl --tlsv1.3 https://example.com                  # 要求 TLS 1.3

# 指定密码套件
curl --ciphers ECDHE-RSA-AES128-GCM-SHA256 https://example.com

# 使用客户端证书(mTLS)
curl --cert client.pem --key client-key.pem \
     --cacert ca.pem \
     https://mtls.example.com/api

# 跳过证书验证(仅调试用!)
curl -k https://self-signed.example.com

# 使用指定 CA 证书
curl --cacert /path/to/custom-ca.pem https://internal.example.com

1.7 HTTP/2 与协议协商

# 强制使用 HTTP/2
curl --http2 -v https://example.com 2>&1 | grep "ALPN\|HTTP/2"

# 使用 HTTP/1.1(禁用 HTTP/2)
curl --http1.1 https://example.com

# 查看 ALPN 协商结果
curl -v https://example.com 2>&1 | grep "ALPN"
# * ALPN: offers h2,http/1.1
# * ALPN: server accepted h2

# 明文 HTTP/2(h2c,仅限本地调试)
curl --http2-prior-knowledge http://localhost:8080/api

二、Chrome DevTools Network:可视化请求分析

Chrome DevTools 的 Network 面板是前端和全栈工程师最常用的 HTTP 调试工具。它提供了比 curl 更直观的可视化分析能力。

2.1 Network 面板核心功能

Network 面板的关键区域:

┌─────────────────────────────────────────────────────────────┐
│ [Filter Bar]  XHR | JS | CSS | Img | Media | Font | Doc    │
│ □ Preserve log   □ Disable cache   □ No throttling ▼       │
├─────┬──────────┬────────┬──────┬──────┬───────────────────┤
│Name │ Status   │ Type   │ Size │ Time │ Waterfall          │
├─────┼──────────┼────────┼──────┼──────┼───────────────────┤
│api/v│ 200      │ fetch  │ 1.2KB│ 234ms│ ████              │
│style│ 200      │ style  │ 45KB │ 89ms │ ██                │
│app.j│ 200      │ script │ 180KB│ 456ms│ ██████████        │
│logo │ 304      │ png    │ 0    │ 12ms │ █                 │
└─────┴──────────┴────────┴──────┴──────┴───────────────────┘

关键选项说明:
- Preserve log: 跨页面导航保留日志(调试重定向必开)
- Disable cache: 禁用缓存(模拟首次访问)
- Throttling: 模拟慢速网络(3G/Slow 3G)

2.2 Timing 面板:请求阶段分解

单击一个请求,切换到 Timing 标签,可以看到请求的每个阶段耗时:

Request Timing 分解:

Queueing           0.12ms   ← 在浏览器队列中等待
Stalled            2.34ms   ← 等待可用连接(受限于同域 6 连接)
DNS Lookup         4.56ms   ← DNS 解析
Initial connection 23.45ms  ← TCP 连接建立
SSL                34.56ms  ← TLS 握手
Request sent        0.23ms  ← 请求发送
Waiting (TTFB)    145.67ms  ← 等待服务端响应(最关键指标)
Content Download   12.34ms  ← 响应内容下载

总时间: 223.27ms

各阶段问题诊断:
- Queueing 长:   浏览器队列拥塞,请求过多或优先级低
- Stalled 长:    连接池用尽,检查是否有同域并发限制
- DNS Lookup 长: DNS 配置问题,考虑 DNS 预取
- SSL 长:       证书链验证慢,考虑 OCSP Stapling
- TTFB 长:      服务端处理慢,需要后端优化
- Download 长:   响应体过大,考虑压缩或分页

2.3 过滤与搜索

Filter Bar 的高级过滤语法:

# 按域名过滤
domain:api.example.com

# 按状态码过滤
status-code:500
status-code:304

# 按大小过滤
larger-than:100k
larger-than:1M

# 按类型过滤
mime-type:application/json

# 按方法过滤
method:POST

# 按头字段过滤
has-response-header:set-cookie

# 按 Cookie 过滤
cookie-domain:example.com
cookie-name:session

# 多条件组合
domain:api.example.com status-code:500 method:POST

# 正则匹配
/api\/v[12]\/.*/

# 排除特定请求(减号前缀)
-domain:cdn.example.com
-status-code:200

2.4 请求阻断与改写

DevTools 可以阻断或修改请求,无需改代码:

请求阻断(Request Blocking):
1. 打开 Network 面板
2. Ctrl+Shift+P → 输入 "block" → 选 "Show Request Blocking"
3. 添加 URL 模式: *.analytics.com
   效果: 所有匹配的请求返回 ERR_BLOCKED_BY_CLIENT

用途:
- 测试第三方脚本加载失败时的降级行为
- 验证 CSP 策略效果
- 排除特定资源对性能的影响

Local Overrides(本地覆盖):
1. Sources → Overrides → 选择本地文件夹
2. Network → 右键请求 → Override content
3. 修改响应内容,刷新页面生效

用途:
- 修改 API 响应测试前端边界情况
- 修改 CSS/JS 而不改服务端
- 添加/修改响应头测试安全头配置

2.5 Copy as cURL:桥接浏览器与命令行

操作: 右键请求 → Copy → Copy as cURL

复制结果包含浏览器发送的完整请求信息:
- URL、Method
- 所有 Headers(包括 Cookie、Authorization)
- Request Body(POST/PUT)
- 压缩接受头(Accept-Encoding)

curl 'https://api.example.com/users' \
  -H 'accept: application/json' \
  -H 'authorization: Bearer eyJ...' \
  -H 'cookie: session=abc123' \
  -H 'user-agent: Mozilla/5.0 ...' \
  --compressed

技巧:
- 在终端重放浏览器请求,验证是否是前端问题
- 修改参数重复测试
- 分享给后端同事复现问题
- 导入 Postman/Insomnia 保存为接口测试用例

2.6 Performance Insights:Waterfall 深度分析

Waterfall 列的颜色含义:

████  绿色  — 等待响应 (TTFB)
████  蓝色  — 内容下载
████  橙色  — SSL/TLS 握手
████  灰色  — 排队/阻塞
████  白色  — DNS 查询

关键模式识别:

1. 阶梯式瀑布(Staircase)
   请求串行执行,一个完成后才开始下一个
   原因: 资源有依赖关系或请求链过长
   优化: 减少请求链深度,使用 preload 预加载

2. 长尾请求(Long Tail)
   大部分请求很快完成,少数请求耗时极长
   原因: 慢 API、大文件下载、第三方资源
   优化: 异步加载、设置超时、使用 CDN

3. 并发饱和(Saturated Parallel)
   6 条请求并行,后续排队等待
   原因: HTTP/1.1 同域 6 连接限制
   优化: 升级 HTTP/2、域名拆分(权宜之计)

三、mitmproxy:可编程的中间人代理

mitmproxy 是一个交互式的 HTTPS 代理,可以拦截、查看、修改和重放 HTTP/HTTPS 流量。它比浏览器 DevTools 更灵活,比 curl 更适合持续监控。

3.1 安装与基本使用

# 安装
pip install mitmproxy

# 三种模式:
mitmproxy    # 终端交互 UI
mitmweb      # Web 界面(推荐初学者)
mitmdump     # 命令行模式(适合脚本集成)

# 启动(默认监听 8080 端口)
mitmproxy -p 8080

# 配置系统代理或应用代理
export http_proxy=http://127.0.0.1:8080
export https_proxy=http://127.0.0.1:8080

# curl 通过 mitmproxy
curl -x http://127.0.0.1:8080 https://api.example.com/health

# 安装 CA 证书(HTTPS 拦截需要)
# 启动 mitmproxy 后访问 http://mitm.it 下载对应平台的证书

3.2 交互式操作

mitmproxy 终端界面操作:

快捷键:
  j/k       上下移动选择请求
  Enter     查看请求详情
  q         返回/退出
  Tab       在 Request/Response/Detail 间切换
  e         编辑请求/响应
  r         重放请求
  z         清空列表
  f         设置过滤器
  /         搜索
  :         命令模式

过滤表达式:
  ~d example.com         按域名过滤
  ~m POST                按方法过滤
  ~c 500                 按响应码过滤
  ~t application/json    按 Content-Type 过滤
  ~b "error"             按 body 内容过滤
  ~h "Authorization"     按头字段过滤
  ~u /api/               按 URL 路径过滤
  ~s                     只显示响应
  ~q                     只显示请求
  ! ~d cdn.example.com   排除特定域名

3.3 mitmdump 脚本:自动化流量分析

mitmproxy 的脚本接口允许用 Python 编写自定义的流量处理逻辑:

# slow_api_detector.py — 检测慢 API 响应
import mitmproxy.http
import time

class SlowAPIDetector:
    def __init__(self):
        self.threshold_ms = 500  # 超过 500ms 视为慢请求

    def request(self, flow: mitmproxy.http.HTTPFlow):
        flow.metadata["start_time"] = time.time()

    def response(self, flow: mitmproxy.http.HTTPFlow):
        start = flow.metadata.get("start_time", 0)
        duration_ms = (time.time() - start) * 1000

        if duration_ms > self.threshold_ms:
            print(f"[SLOW] {duration_ms:.0f}ms "
                  f"{flow.request.method} {flow.request.pretty_url} "
                  f"→ {flow.response.status_code}")

addons = [SlowAPIDetector()]
# response_modifier.py — 修改响应内容(模拟故障)
import mitmproxy.http
import json

class ResponseModifier:
    def response(self, flow: mitmproxy.http.HTTPFlow):
        # 注入延迟头以帮助调试
        flow.response.headers["X-Debug-Via"] = "mitmproxy"

        # 模拟 API 降级:将特定 API 的响应改为错误
        if "/api/payment" in flow.request.pretty_url:
            flow.response.status_code = 503
            flow.response.text = json.dumps({
                "error": "Service temporarily unavailable",
                "retry_after": 30
            })

        # 移除安全头进行测试
        if flow.request.pretty_url.endswith("/test-no-csp"):
            flow.response.headers.pop("Content-Security-Policy", None)

addons = [ResponseModifier()]
# 运行脚本
mitmdump -s slow_api_detector.py
mitmdump -s response_modifier.py

# 同时使用多个脚本
mitmdump -s slow_api_detector.py -s response_modifier.py

3.4 流量录制与重放

# 录制流量到文件
mitmdump -w traffic.flow

# 回放录制的流量
mitmdump -c traffic.flow

# 服务端回放(将录制的响应作为 mock 返回)
mitmdump --server-replay traffic.flow \
    --server-replay-nopop \
    --server-replay-kill-extra

# 用途:
# 1. 录制生产环境流量 → 本地回放调试
# 2. 接口测试:录制正常响应 → 作为 mock server
# 3. 对比分析:录制修改前后的流量差异

3.5 移动端 HTTP 调试

移动端调试步骤:

1. 确保手机和电脑在同一网络
2. 启动 mitmproxy:
   mitmweb --listen-host 0.0.0.0 -p 8080
3. 手机 WiFi 设置代理: 电脑IP:8080
4. 手机浏览器访问 http://mitm.it 安装 CA 证书
   iOS: 设置 → 通用 → 关于 → 证书信任设置 → 启用
   Android: 设置 → 安全 → 安装证书

5. 手机上的所有 HTTP/HTTPS 流量都会经过 mitmproxy

常见问题:
  证书固定(Certificate Pinning)的 App 会拒绝 mitmproxy 的证书
  解决方案:
    - Android: 使用 Frida 动态 hook SSL 验证
    - iOS: 使用 SSL Kill Switch 2(需越狱)
    - 大多数调试场景可使用应用自带的 debug 构建

四、HTTP 性能分析方法论

HTTP 性能问题的根因可能在网络、服务端或客户端。系统化的分析方法是找到瓶颈的关键。

4.1 TTFB 分解

TTFB(Time To First Byte,首字节时间)是 HTTP 性能的核心指标,它是用户感知延迟的最大组成部分。

TTFB 的组成:

TTFB = DNS + TCP + TLS + Server Processing

┌──────────┬─────────────┬──────────────┬─────────────────────┐
│ DNS 解析  │ TCP 三次握手 │ TLS 握手     │ 服务端处理           │
│ 2-50ms   │ 1-100ms     │ 10-200ms    │ 10ms-数秒            │
└──────────┴─────────────┴──────────────┴─────────────────────┘
├─────────────── TTFB ─────────────────────────────────────────┤

各阶段优化方向:
  DNS:     使用快速 DNS、DNS 预取、减少 CNAME 链
  TCP:     启用 TFO、减少 RTT(使用 CDN)
  TLS:     TLS 1.3、Session Resumption、OCSP Stapling
  Server:  应用层优化、缓存、数据库优化

# 使用 curl 测量 TTFB
curl -s -o /dev/null -w "TTFB: %{time_starttransfer}s\n" https://example.com

# 多次测量取中位数
for i in $(seq 1 20); do
    curl -s -o /dev/null \
        -w "%{time_starttransfer}\n" \
        https://example.com
done | sort -n | awk 'NR==10{printf "P50 TTFB: %.3fms\n", $1*1000}'

4.2 HTTP 延迟分类与诊断

延迟类型          │ 表现                    │ 诊断方法
──────────────────┼─────────────────────────┼──────────────────────────
网络延迟          │ TCP RTT 高              │ ping/mtr, curl timing
DNS 延迟          │ 首次访问慢,后续正常      │ dig, time_namelookup
TLS 延迟          │ HTTPS 比 HTTP 慢很多     │ curl --tlsv1.3, openssl s_time
服务端延迟        │ TTFB 高,网络 RTT 正常    │ 服务端 APM, access log
传输延迟          │ 下载时间长               │ Content-Length, 压缩检查
队头阻塞          │ 请求排队,Stalled 时间长  │ DevTools Waterfall
重定向延迟        │ 多次 3xx 跳转            │ curl -L -w redirects

4.3 端到端请求链路追踪

在微服务架构中,一个 HTTP 请求可能经过多层代理和多个服务。追踪完整链路需要利用请求 ID:

# 步骤 1: 发送带追踪 ID 的请求
REQUEST_ID="debug-$(date +%s)-$(( RANDOM % 1000 ))"
curl -v \
    -H "X-Request-ID: $REQUEST_ID" \
    -H "X-Debug: true" \
    https://api.example.com/orders/123

# 步骤 2: 在各层日志中搜索该 ID

# Nginx access log
grep "$REQUEST_ID" /var/log/nginx/access.log

# 应用日志
grep "$REQUEST_ID" /var/log/app/application.log

# 上游服务日志
grep "$REQUEST_ID" /var/log/upstream/service.log

# 步骤 3: 对比各层的时间戳,找到延迟瓶颈
# Nginx:    10:00:00.100 → 10:00:00.500  (400ms, 代理处理)
# App:      10:00:00.110 → 10:00:00.480  (370ms, 应用处理)
# Database: 10:00:00.120 → 10:00:00.450  (330ms, 数据库查询!)
#
# 结论: 延迟主要来自数据库查询
# 检查各层添加的响应头
curl -s -D - -o /dev/null https://api.example.com/orders/123 | \
    grep -iE "^(x-|via|server|age|cf-)"

# 常见的调试响应头:
# X-Request-ID: abc123             ← 请求追踪 ID
# X-Response-Time: 0.234           ← 服务端处理时间
# Via: 1.1 proxy1, 1.1 proxy2     ← 经过的代理链
# X-Cache: HIT from cdn-edge-01   ← CDN 缓存命中
# Age: 3600                       ← 缓存已存在时间
# Server: nginx/1.24.0            ← 服务端软件
# CF-Ray: 8a1234567890abcd-SJC    ← Cloudflare 请求 ID

五、专题调试场景

5.1 HTTPS 证书问题排查

# 查看证书链完整信息
openssl s_client -connect example.com:443 -showcerts 2>/dev/null | \
    openssl x509 -noout -text | \
    grep -A 2 "Issuer:\|Subject:\|Not After\|DNS:"

# 检查证书过期时间
echo | openssl s_client -connect example.com:443 2>/dev/null | \
    openssl x509 -noout -dates
# notBefore=Jan  1 00:00:00 2025 GMT
# notAfter=Mar 31 23:59:59 2025 GMT

# 验证证书链完整性
openssl s_client -connect example.com:443 \
    -CAfile /etc/ssl/certs/ca-certificates.crt 2>&1 | \
    grep "Verify return code"
# Verify return code: 0 (ok)

# 常见错误码:
# 10 — 证书过期
# 18 — 自签名证书
# 19 — CA 未知(证书链不完整)
# 20 — 无法找到本地颁发者证书
# 21 — 证书链过长

# 测试特定协议和密码套件
openssl s_client -connect example.com:443 \
    -tls1_2 -cipher ECDHE-RSA-AES128-GCM-SHA256

5.2 重定向链分析

# 跟踪完整的重定向链
curl -v -L https://example.com 2>&1 | grep -E "< HTTP|< location"

# 使用 -w 获取重定向统计
curl -s -o /dev/null -L -w \
    "Redirects: %{num_redirects}\nFinal URL: %{url_effective}\nTotal: %{time_total}s\n" \
    http://example.com

# 最大重定向次数(防止无限循环)
curl -L --max-redirs 5 http://example.com

# 常见重定向问题:
# 1. HTTP → HTTPS 重定向未设置 HSTS
# 2. www → non-www 重定向循环
# 3. Trailing slash 重定向浪费一次 RTT
# 4. 过长的重定向链(>3 次)增加延迟

5.3 缓存行为验证

# 验证缓存头
curl -s -D - -o /dev/null https://example.com/style.css | \
    grep -iE "^(cache-control|etag|last-modified|age|expires|vary):"

# 条件请求验证
ETAG=$(curl -sI https://example.com/style.css | grep -i etag | tr -d '\r')
curl -v -H "If-None-Match: ${ETAG#*: }" https://example.com/style.css
# 期望: HTTP 304 Not Modified

# Last-Modified 条件请求
LM=$(curl -sI https://example.com/style.css | grep -i "last-modified" | cut -d: -f2-)
curl -v -H "If-Modified-Since:$LM" https://example.com/style.css
# 期望: HTTP 304 Not Modified

# 验证 CDN 缓存命中
for i in 1 2 3; do
    echo "--- Request $i ---"
    curl -sI https://cdn.example.com/image.jpg | \
        grep -iE "^(x-cache|age|cf-cache-status):"
    sleep 1
done
# 第 1 次: X-Cache: MISS, Age: 0
# 第 2 次: X-Cache: HIT,  Age: 1
# 第 3 次: X-Cache: HIT,  Age: 2

5.4 HTTP/2 调试

# 验证 HTTP/2 支持
curl -v --http2 https://example.com 2>&1 | grep "HTTP/2"

# 使用 nghttp 查看帧级别信息
nghttp -v https://example.com 2>&1 | head -30
# [  0.023] Connected
# [  0.045] recv SETTINGS frame
# [  0.045] recv WINDOW_UPDATE frame
# [  0.045] send HEADERS frame
# [  0.067] recv HEADERS frame
# [  0.067] recv DATA frame

# 查看 HTTP/2 连接信息
curl -v --http2 https://example.com 2>&1 | \
    grep -E "ALPN|HTTP/2|stream"

# 检测服务端是否支持 Server Push(已基本废弃)
nghttp -v https://example.com 2>&1 | grep "PUSH_PROMISE"

六、调试工具对比与选型

工具          │ 最佳场景              │ 优势                     │ 局限
──────────────┼───────────────────────┼──────────────────────────┼──────────────
curl          │ 快速单请求测试        │ 无依赖、精确控制、脚本化  │ 无法拦截浏览器流量
              │ 服务端接口调试        │ TLS/协议级诊断            │ 无可视化
              │ CI/CD 自动化测试      │                          │
──────────────┼───────────────────────┼──────────────────────────┼──────────────
DevTools      │ 前端/全栈开发调试     │ 可视化、Waterfall 分析   │ 仅限浏览器流量
              │ 页面加载性能分析      │ 与浏览器深度集成          │ 无法拦截改写
              │ 快速复现前端问题      │ Copy as cURL 联动        │
──────────────┼───────────────────────┼──────────────────────────┼──────────────
mitmproxy     │ HTTPS 拦截与改写      │ 可编程、支持脚本扩展     │ 需要安装 CA 证书
              │ 移动端 App 调试       │ 流量录制/重放            │ Certificate Pinning
              │ 故障注入/模拟降级     │ 支持 HTTP/2              │ 配置较复杂
──────────────┼───────────────────────┼──────────────────────────┼──────────────
Wireshark     │ 协议级深度分析        │ 逐包分析、支持所有协议    │ 无法解密 HTTPS
              │ TCP/TLS 层面排查      │ 专家信息与流图            │ 学习曲线陡
              │ 抓包离线分析          │ 强大的过滤表达式          │ 不适合日常调试
──────────────┼───────────────────────┼──────────────────────────┼──────────────
httpie        │ API 开发测试          │ 语法友好、JSON 高亮      │ 功能不如 curl 全面
              │ REST 接口快速测试     │ 默认行为更合理            │ 安装需要 Python
调试决策流程:

浏览器中的页面加载问题?
  → Chrome DevTools

服务端 API 接口问题?
  → curl(快速测试)
  → curl + timing 模板(性能分析)

需要拦截/修改 HTTPS 流量?
  → mitmproxy

移动 App 的网络问题?
  → mitmproxy(代理模式)

TCP/TLS 层面的连接问题?
  → Wireshark + tcpdump

自动化测试/监控?
  → curl + 脚本
  → mitmdump + Python 脚本

七、总结

HTTP 调试的核心是”分层隔离”——把问题定位到 DNS、TCP、TLS、应用层中的某一层,再用针对性的工具深入分析。

  1. curl 是最基础的工具。掌握 -v--trace--resolve-w 四个参数就能解决大部分调试需求。timing 模板是分析 HTTP 性能的利器。

  2. DevTools 提供直观的可视化分析。Waterfall 图可以快速定位并发瓶颈和串行瓶颈。“Copy as cURL”是连接浏览器和命令行的桥梁。

  3. mitmproxy 是 HTTPS 调试的最强工具。可编程的脚本接口让它能胜任流量分析、故障注入、自动化测试等复杂场景。

  4. TTFB 是 HTTP 性能的核心指标。将 TTFB 分解为 DNS + TCP + TLS + Server Processing,就能精确定位性能瓶颈。

  5. 请求 ID 是微服务环境中追踪问题的命脉。从入口到最后一个后端服务,保持同一个 X-Request-ID,就能在分布式日志中还原完整链路。

  6. 工具选型要匹配场景。日常开发用 DevTools,服务端接口用 curl,HTTPS 拦截用 mitmproxy,协议层分析用 Wireshark。不存在一个工具解决所有问题。


参考文献


上一篇:HTTP 安全头完整实战:CORS、CSP、HSTS

下一篇:WebSocket 工程:握手、帧格式与大规模运维

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2025-07-23 · network

【网络工程】零拷贝网络:sendfile、splice 与 MSG_ZEROCOPY

数据从磁盘到网卡的传统路径涉及 4 次拷贝和多次上下文切换。本文系统剖析 sendfile、splice、vmsplice、MSG_ZEROCOPY 四种零拷贝技术的内核实现、适用场景与性能差异,并以 Kafka 和 Nginx 为案例分析零拷贝在生产系统中的工程实践。


By .