Wireshark 是常用的网络抓包和协议分析工具。它适合回答这些问题:
- 程序连了哪个域名和 IP。
- 请求和响应是否正常。
- DNS 是否解析失败。
- TCP 是否重传、丢包或握手失败。
- HTTP 参数、状态码、响应体是什么。
- TLS 握手是否失败,证书是否异常。
抓包前先明确边界:只抓自己设备、自己网络、授权测试环境中的流量。不要在公共网络或他人设备上抓取敏感数据。
抓包前准备
先确认目标:
| 问题 | 关注点 |
|---|---|
| 接口请求失败 | DNS、TCP、TLS、HTTP 状态码 |
| 上传慢 | TCP 重传、窗口、RTT、服务端响应 |
| App 连不上 | 代理、证书、SNI、域名解析 |
| 协议未知 | 端口、payload、握手特征 |
| 偶发错误 | 时间线、重试、连接复用 |
记录信息:
1 | - 设备: |
选择网卡
打开 Wireshark 后选择正在通信的网卡:
| 场景 | 常见网卡 |
|---|---|
| 本机浏览网页 | Wi-Fi / Ethernet |
| Android 代理到电脑 | Wi-Fi / Ethernet |
| 本机回环请求 | Loopback |
| Docker / 虚拟机 | bridge / vmnet / vEthernet |
如果不确定,先看哪个网卡有波形。
捕获过滤器与显示过滤器
Wireshark 有两类过滤器:
| 类型 | 生效时机 | 示例 |
|---|---|---|
| 捕获过滤器 | 抓包前,只保存匹配流量 | host 1.2.3.4 |
| 显示过滤器 | 抓包后,只显示匹配包 | ip.addr == 1.2.3.4 |
捕获过滤器语法更接近 tcpdump:
1 | host 1.2.3.4 |
显示过滤器更强大:
1 | ip.addr == 1.2.3.4 |
入门建议:先不设捕获过滤器,抓完后用显示过滤器查。
常用显示过滤器
IP 和端口
1 | ip.addr == 192.168.1.10 |
DNS
1 | dns |
DNS 返回码:
| rcode | 含义 |
|---|---|
0 |
成功 |
2 |
Server failure |
3 |
NXDOMAIN,域名不存在 |
5 |
Refused |
TCP
1 | tcp |
TLS
1 | tls |
TLS 握手类型:
| type | 含义 |
|---|---|
1 |
Client Hello |
2 |
Server Hello |
11 |
Certificate |
15 |
Certificate Verify |
20 |
Finished |
HTTP
1 | http |
HTTPS 默认看不到 HTTP 明文,除非你有合法的解密条件,例如测试环境密钥、浏览器 SSL key log 或代理导出的明文。
Follow TCP Stream
看到某个 TCP 包后:
1 | 右键 -> Follow -> TCP Stream |
适合看:
- HTTP 明文请求。
- 自定义 TCP 协议。
- 服务端返回内容。
- 一次连接内的请求响应顺序。
注意:
- TCP Stream 是按连接重组,不等于业务请求。
- HTTP/2、WebSocket、TLS 加密流需要对应解析方式。
- 长连接里可能有多次业务消息。
分析 DNS 问题
典型过滤:
1 | dns.qry.name contains "api.example.com" |
检查:
- 是否发出查询。
- 查询的是 A 还是 AAAA。
- 是否有响应。
- 响应 IP 是什么。
- rcode 是否为 0。
- 是否频繁重试。
常见现象:
| 现象 | 可能原因 |
|---|---|
| 没有 DNS 请求 | 使用缓存、直接 IP、DoH、代理 |
| NXDOMAIN | 域名不存在或环境配置错误 |
| 只有 AAAA 失败 | IPv6 环境问题 |
| DNS 很慢 | DNS 服务器或网络延迟 |
分析 TCP 连接失败
过滤目标 IP:
1 | ip.addr == 1.2.3.4 and tcp |
看握手:
1 | tcp.flags.syn == 1 |
正常三次握手:
1 | Client -> Server SYN |
异常现象:
| 现象 | 可能原因 |
|---|---|
| SYN 一直重传 | 服务不可达、防火墙、路由问题 |
| 收到 RST | 端口关闭、服务拒绝、代理重置 |
| 握手成功后无数据 | 应用未发送、TLS 卡住、代理问题 |
| 大量重传 | 丢包、网络质量差、MTU 问题 |
分析 TLS 问题
过滤:
1 | tls.handshake |
关注:
- Client Hello 里 SNI 是否正确。
- TLS 版本。
- Cipher Suites。
- Server Hello 是否返回。
- Certificate 是否下发。
- Alert 类型。
TLS Alert 过滤:
1 | tls.alert_message |
常见问题:
| 现象 | 可能原因 |
|---|---|
| 没有 Server Hello | 服务端拒绝或网络中断 |
| Certificate 后失败 | 证书校验失败、系统时间错误 |
| Unknown CA | 测试证书未信任 |
| Handshake Failure | TLS 版本或加密套件不匹配 |
HTTP 分析
明文 HTTP 可直接看请求:
1 | http.request.method == "POST" |
常看字段:
- Method
- Host
- URI
- Status Code
- Content-Type
- User-Agent
- Cookie
- Authorization
- Request Payload
- Response Body
导出对象:
1 | File -> Export Objects -> HTTP |
如果是 gzip 响应,Wireshark 通常能自动解压。不能解压时检查 Content-Encoding。
HTTPS 解密:SSLKEYLOGFILE
对于自己浏览器访问的测试站点,可以用浏览器导出会话密钥。
macOS / Linux:
1 | export SSLKEYLOGFILE=/tmp/sslkeys.log |
Windows PowerShell:
1 | $env:SSLKEYLOGFILE="C:\temp\sslkeys.log" |
Wireshark 设置:
1 | Preferences -> Protocols -> TLS -> (Pre)-Master-Secret log filename |
选择 sslkeys.log 后,Wireshark 可以解密对应浏览器会话。
注意:
- 只对支持 key log 的客户端有效。
- 只能解密你自己产生且有 key log 的流量。
- App 不一定支持这种方式。
- HTTP/2 解密后可能显示为
http2。
命令行 tshark
查看网卡:
1 | tshark -D |
抓 30 秒保存:
1 | tshark -i en0 -a duration:30 -w capture.pcapng |
过滤显示 DNS:
1 | tshark -r capture.pcapng -Y "dns" -T fields \ |
导出 HTTP 状态码:
1 | tshark -r capture.pcapng -Y "http.response" -T fields \ |
统计目标 IP:
1 | tshark -r capture.pcapng -T fields -e ip.dst | |
Python 读取 pcap
如果安装了 pyshark:
1 | import pyshark |
用 tshark 输出 JSON 再让 Python 处理也很稳:
1 | tshark -r capture.pcapng -Y "dns" -T json > dns.json |
Python:
1 | import json |
小案例:接口偶发 502
目标:分析 api.example.com 偶发 502。
步骤:
- 开始抓包。
- 触发接口请求。
- 记录发生问题的时间。
- 过滤域名:
1 | dns.qry.name contains "api.example.com" |
- 找到解析 IP。
- 过滤 IP:
1 | ip.addr == 1.2.3.4 |
- 查看 TCP 是否重传:
1 | ip.addr == 1.2.3.4 and tcp.analysis.retransmission |
- 如果是明文或可解密 HTTP,查状态码:
1 | http.response.code == 502 |
记录:
1 | - DNS 解析正常,返回 `1.2.3.4`。 |
完整案例:从“App 网络异常”定位 TLS 证书问题
场景:测试 App 请求 https://api.test.local/user/profile 失败,客户端只提示“网络异常”。目标是判断问题发生在 DNS、TCP、TLS 还是 HTTP。
1. 抓包前记录
1 | - 设备:Android 测试机 |
2. 看 DNS
显示过滤器:
1 | dns.qry.name contains "api.test.local" |
如果看到:
1 | Standard query A api.test.local |
说明 DNS 正常。
3. 看 TCP
过滤:
1 | ip.addr == 10.10.20.15 and tcp.port == 443 |
正常三次握手应该是:
1 | Client -> Server SYN |
如果出现 SYN 重传:
1 | tcp.analysis.retransmission and ip.addr == 10.10.20.15 |
问题可能在网络、防火墙或服务端端口。本案例假设 TCP 正常。
4. 看 TLS
过滤:
1 | tls.handshake or tls.alert_message |
看到:
1 | Client Hello, SNI: api.test.local |
说明:
- SNI 正确。
- 服务端有响应。
- 失败发生在证书校验阶段。
Unknown CA指向客户端不信任服务端证书链。
5. 用 tshark 导出证据
1 | tshark -r app-fail.pcapng -Y "tls.alert_message" -T fields \ |
示例:
1 | May 31, 2026 10:32:16.123456 192.168.1.23 10.10.20.15 Unknown CA |
DNS 摘要:
1 | tshark -r app-fail.pcapng -Y "dns.qry.name contains api.test.local" -T fields \ |
6. 结论
1 | 本次“网络异常”发生在 TLS 证书校验阶段。 |
完整案例:HTTP 500 是客户端参数错还是服务端异常
场景:测试环境接口偶发 HTTP 500。你已经通过 SSLKEYLOGFILE 解密了浏览器流量。
1. 过滤 500 响应
1 | http.response.code == 500 |
查看目标接口:
1 | http.request.uri contains "/api/order/create" |
2. Follow HTTP Stream
右键其中一个 500 响应:
1 | Follow -> HTTP Stream |
失败请求:
1 | POST /api/order/create |
失败响应:
1 | 500 Internal Server Error |
成功请求:
1 | {"sku_id":"A1001","count":1} |
3. 判断
可以写成:
1 | HTTP 500 与请求体中的空 `sku_id` 相关。 |
常见问题
为什么抓不到包
可能原因:
- 选错网卡。
- 流量走了代理、VPN 或其他接口。
- 目标在本机回环,但抓的是 Wi-Fi。
- 没有权限抓包。
- App 使用 QUIC / HTTP3,走 UDP 443。
先用简单过滤确认是否有流量:
1 | ip |
为什么 HTTPS 看不到内容
HTTPS 是加密的。Wireshark 默认只能看到:
- IP。
- 端口。
- TLS 握手。
- SNI。
- 证书。
- 包大小和时间。
看明文需要合法解密条件,如 SSLKEYLOGFILE、测试代理或服务端私钥配合旧式 RSA 握手。现代 TLS 通常不能仅凭服务端私钥解密。
为什么只有 HTTP/2 看不懂
HTTP/2 是二进制协议。解密后 Wireshark 会显示 http2 帧。关注:
1 | http2.headers |
可以在 Follow Stream 里看重组内容,但不如 HTTP/1.1 直观。
大量 TCP 重传一定是服务端问题吗
不一定。重传可能来自:
- 客户端网络差。
- Wi-Fi 丢包。
- VPN 或代理。
- 中间链路拥塞。
- 服务端响应慢导致超时重试。
要结合 RTT、重传方向和时间线判断。
QUIC / HTTP3 怎么看
QUIC 通常走 UDP 443:
1 | udp.port == 443 |
如果只是想排查 HTTP 行为,可以在浏览器或测试环境临时关闭 QUIC;如果是 App,要看它是否支持切换协议。
抓包记录模板
1 | ## 场景 |
dns.qry.name contains “example” ip.addr == x.x.x.x tcp.analysis.retransmission
1 |
|
案例三:定位接口慢是 DNS、建连还是服务端处理慢
场景
测试环境反馈:App 点击登录后等 5 秒才返回。服务端说接口只处理了 80ms,客户端说就是慢。用 Wireshark 拆时间线。
1. 过滤目标域名 DNS
1 | dns.qry.name contains "api.demo.local" |
关注:
| 字段 | 说明 |
|---|---|
| Query 到 Response 间隔 | DNS 解析耗时 |
| 返回 IP | 是否符合预期环境 |
| 是否重复查询 | 是否 DNS 缓存失效或失败重试 |
如果 DNS 就用了 3 秒,先不要看 HTTP。
2. 过滤目标 IP
假设解析到 10.10.20.8:
1 | ip.addr == 10.10.20.8 |
看 TCP 三次握手:
1 | tcp.flags.syn == 1 || tcp.flags.ack == 1 |
计算:
1 | SYN -> SYN,ACK |
这个时间接近网络 RTT。如果 SYN 重传:
1 | tcp.analysis.retransmission && tcp.flags.syn == 1 |
说明连接阶段就不稳定。
3. 看 TLS 握手
1 | tls.handshake |
关注:
- Client Hello。
- Server Hello。
- Certificate。
- Finished。
如果 TLS 握手前后卡很久,可能是证书链、代理、网络或服务端 TLS 配置问题。
4. 看 HTTP 请求到响应
如果能解密 HTTP:
1 | http.request || http.response |
或者 HTTP/2:
1 | http2.headers |
计算:
1 | request headers -> response headers |
如果这段是 80ms,但总耗时 5 秒,那么慢点在 DNS、TCP 或 TLS;如果这段就是 5 秒,才看服务端。
5. tshark 导出时间线
1 | tshark -r login.pcapng \ |
记录模板:
1 | | 阶段 | 起止包 | 耗时 | 结论 | |
这个案例最后的结论可能是:登录慢不是接口处理慢,而是测试 Wi-Fi 的 DNS 服务器响应慢。
案例四:确认客户端是否真的发出了 JSON 字段
场景
服务端报错:
1 | missing field: device_id |
客户端开发说代码里已经传了。用抓包确认线上实际请求。
1. 过滤接口
如果是 HTTP 明文:
1 | http.request.uri contains "/api/device/bind" |
如果是已解密 HTTPS/HTTP2:
1 | http2.headers.path contains "/api/device/bind" |
2. Follow Stream
右键目标包:
1 | Follow -> HTTP Stream |
检查请求体:
1 | { |
如果服务端要求 device_id,而客户端发的是 deviceId,问题就不是网络,是字段命名不一致。
3. 用 tshark 导出请求体
HTTP/1.1 明文:
1 | tshark -r bind.pcapng \ |
如果输出十六进制或转义内容,可以先导出对象,或者在 Wireshark 的 Packet Bytes 里复制为 printable text。
4. 结论写法
1 | - 接口:`POST /api/device/bind` |
案例五:判断 WebSocket 心跳是否断了
场景
页面显示“设备离线”,但设备端日志说自己一直在线。抓浏览器到网关的 WebSocket。
1. 过滤 WebSocket
1 | websocket |
或者先找升级请求:
1 | http.request && http.request.line contains "Upgrade: websocket" |
2. 看握手
正常握手应该看到:
1 | GET /ws/device HTTP/1.1 |
响应:
1 | HTTP/1.1 101 Switching Protocols |
如果没有 101,先看鉴权、路径和代理配置。
3. 看心跳帧
Wireshark 过滤:
1 | websocket.payload contains "ping" || websocket.payload contains "pong" |
如果是标准控制帧:
1 | websocket.opcode == 9 || websocket.opcode == 10 |
4. 判断断线位置
| 现象 | 可能原因 |
|---|---|
| 客户端持续发 ping,服务端不回 pong | 服务端卡住、网关丢弃、反向代理超时 |
| 服务端发消息,客户端 TCP ACK 正常但页面没更新 | 前端业务处理问题 |
| 出现 TCP FIN | 一方主动关闭 |
| 出现 TCP RST | 连接被重置,常见于代理或进程异常 |
5. 记录结论
1 | - WebSocket 握手:成功,HTTP 101 |