首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Web 协议详解与抓包:从报文到根因的完整实操

Web 协议详解与抓包:从报文到根因的完整实操

原创
作者头像
资源大佬 jzit-top
发布于 2026-10-22 16:40:06
发布于 2026-10-22 16:40:06
990
举报

抓包不是“打开 Wireshark 看一眼”,而是一套从定位抓包点 → 解密 → 逐层读协议 → 归因的方法论。Web 排障的难点在于三层协议叠在一起:TCP 决定“通不通、快不快”,TLS 决定“握没握上、证不证书”,HTTP 决定“语义对不对”。下面按这个顺序给出可执行的命令与代码。

一、抓包点与过滤:先收窄再抓

抓包第一原则是贴着故障侧抓。客户端慢抓客户端网卡,服务端处理慢抓回环,链路问题抓网关。容器里抓 eth0,注意 sidecar 会改变流量路径。抓之前先写 BPF 过滤,避免 pcap 被无关流量撑爆。

代码语言:javascript
复制
# 只抓目标主机与端口,全量载荷,带绝对时间
tcpdump -i eth0 -s 0 -nn -tttt \
  'host 10.0.2.15 and (port 80 or port 443)' -w web.pcap

# 只保留有载荷的 TCP 包(过滤纯 ACK),直接看明文请求行
tcpdump -i eth0 -A -s 0 \
  'tcp port 80 and (((ip[2:2]-((ip[0]&0xf)<<2))-((tcp[12]&0xf0)>>2))!=0)'

第二条表达式用 IP 总长减 IP 头减 TCP 头算载荷长度,非零才打印,日志立刻清爽。

二、HTTPS 解密:keylog 最干净

TLS 让内容不可见,但排障必须解密。生产可用的合法路径是客户端导出会话密钥(SSLKEYLOGFILE),Wireshark 加载后自动解密,不涉及中间人。

代码语言:javascript
复制
export SSLKEYLOGFILE=/tmp/keys.log
curl -v https://api.example.com/health -o /dev/null
# Wireshark: Preferences → Protocols → TLS → (Pre)-Master-Secret log 填 /tmp/keys.log

只做单次请求排查时,用 mitmproxy 插件更方便,还能顺手改写请求头注入 traceId:

代码语言:javascript
复制
# addon.py → mitmproxy -s addon.py
from mitmproxy import http

def request(flow: http.HTTPFlow) -> None:
    if "api.example.com" not in flow.request.pretty_host:
        return
    flow.request.headers["X-Capture-Trace"] = "cap-001"
    print(f"[REQ] {flow.request.method} {flow.request.path}")
    print("  host:", flow.request.headers.get("host"))

def response(flow: http.HTTPFlow) -> None:
    if flow.response.status_code >= 400:
        print(f"[{flow.response.status_code}] {flow.request.path}")
        print(flow.response.text[:300])

解密后第一件事是核对 ClientHello 的 SNI 与 HTTP 的 Host 是否一致——不一致会导致 CDN 返回错误证书或错误站点,是“证书错误”类工单的头号原因。

三、HTTP 报文:三类高发问题

明文 HTTP 要读三处:请求行/响应行的语义、Content-Length 与 Transfer-Encoding 是否冲突、Set-Cookie 的属性组合。

用 Wireshark 显示过滤器快速收敛:http.request.method == "POST"、http.response.code >= 500、http.content_type contains "json"。批量分析用 scapy 还原事务:

代码语言:javascript
复制
from scapy.all import rdpcap, TCP, Raw

def http_requests(path):
    out = []
    for pkt in rdpcap(path):
        if TCP not in pkt or Raw not in pkt:
            continue
        data = pkt[Raw].load
        if data.startswith((b"GET", b"POST", b"PUT", b"DELETE")):
            head = data.split(b"\r\n\r\n")[0].decode("latin1")
            out.append({"ts": float(pkt.time), "head": head})
    return out

for r in http_requests("web.pcap")[:5]:
    print("---", r["ts"])
    print(r["head"][:400])

Content-Length 与 Transfer-Encoding: chunked 同时出现是协议违规,代理行为不确定,直接导致响应截断或挂起。

四、HTTP/2:按帧读,不按行读

HTTP/2 是二进制分帧,看不到请求行。用 tshark 直接按流导出帧,关注 :method、:path、:status 伪头,以及 RST_STREAM 错误码——RST_STREAM 常意味着服务端主动取消或流控异常。

代码语言:javascript
复制
tshark -r web.pcap -Y "http2" \
  -T fields -e http2.streamid -e http2.headers.method \
  -e http2.headers.path -e http2.headers.status -e http2.type

多路复用下一条 TCP 连接承载多个流,读包必须同时看 stream id 与帧类型,否则会误判“请求丢失”。

五、WebSocket:101 之后是帧

握手阶段仍是 HTTP,看 Upgrade: websocket 与 Sec-WebSocket-Accept 是否正确回显;升级成功后转帧视图。抓包过滤器 websocket 直接定位。

代码语言:javascript
复制
const ws = new WebSocket("wss://api.example.com/ws");
ws.onopen = () => ws.send(JSON.stringify({ type: "sub", ch: "ticker" }));
ws.onmessage = e => console.log("frame:", e.data);

常见问题是代理不支持长连接、心跳缺失被中间设备掐断——抓包看 Ping/Pong 帧间隔即可判断。

六、TCP 层:把“慢”翻译成事件

HTTP 慢,九成能在 TCP 层找到答案。用 tshark 统计重传与握手耗时:

代码语言:javascript
复制
tshark -r web.pcap -q -z io,stat,0 \
  -z "io,stat,0,COUNT(tcp.analysis.retransmission)tcp.analysis.retransmission" \
  -z "io,stat,0,AVG(tcp.time_delta)tcp.time_delta"

判据速查:SYN → SYN/ACK 时间差即建连 RTT;重传间隔按 1s/2s/4s 翻倍是丢包;TCP ZeroWindow 是接收方应用读得太慢,问题在应用;TCP Window Full 叠加小载荷是发送窗口被卡。看到 RST 要确认是谁发的,网关 RST 常见于上游超时。

七、归因表与结论

现象

抓包点

关键判据

首屏慢

客户端

建连 RTT、TLS 轮次、队头阻塞

偶发 502

网关

上游 RST、超时值、连接池耗尽

登录态丢失

双端

Set-Cookie 属性、SNI/Host 不一致

上传中断

双向

重传密度、零窗口、PMTU 黑洞

抓包排障的本质是分层归因:HTTP 看语义,TLS 看握手与证书,TCP 看时序与窗口。固定变量(同一时间窗、同一 traceId、同一版本),配好 keylog 解密与 tshark 统计,任何“感觉慢”都能收敛到一行可复现的协议事件——这就是抓包的价值。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、抓包点与过滤:先收窄再抓
  • 二、HTTPS 解密:keylog 最干净
  • 三、HTTP 报文:三类高发问题
  • 四、HTTP/2:按帧读,不按行读
  • 五、WebSocket:101 之后是帧
  • 六、TCP 层:把“慢”翻译成事件
  • 七、归因表与结论
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档