故障排查与常见问题¶
本页汇集了用户在运行 httptap 时最常遇到的问题和错误。如果你的问题未在此列出,请提交 issue,并附上确切的命令、JSON 导出(如有)以及相关的终端输出。
TLS 与证书¶
[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed¶
服务器出示了一个你的信任库无法识别的证书。失败的步骤会报告类似 Request failed: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate (_ssl.c:1077) 的错误;冒号后的原因(自签名、已过期、无法获取本地颁发者证书、主机名不匹配)以及 _ssl.c 的行号会有所不同。
- 非生产主机上的自签名或过期证书 —— 添加
--ignore-ssl(禁用校验,仅在可信网络中使用)。 - 内部 CA —— 将
--cacert(别名--ca-bundle)指向你的 PEM 包。 - 系统信任库已过时 —— 在 Linux 上更新
ca-certificates,或刷新你 Python 环境中的certifi(uv pip install --upgrade certifi)。
httptap 仅会在不校验证书的情况下重试一次诊断性 TLS 握手,并在失败步骤中报告所出示证书的 CN、SAN、颁发者、有效期以及到期时间。请求本身仍会校验失败。当启用代理时,会跳过直连的诊断探测,以免 httptap 绕过代理。
证书显示 cert_days_left: null 或负值¶
cert_days_left 从叶证书的 notAfter 字段解析而来。null 值表示无法获取/解析该证书——通常是 TLS 在收到证书前就已中止、目标是纯 http://,或者请求在 TLS 握手之前就已失败。--ignore-ssl 不会导致该值为空:禁用校验时,httptap 会从对端证书的 DER 形式解析证书,因此 cert_cn、cert_days_left 以及其他 cert_* 字段仍会被报告。**负**值表示证书已过期。
--ignore-ssl 仍以 DH_KEY_TOO_SMALL / WRONG_VERSION_NUMBER 失败¶
现代 OpenSSL 构建出于安全考虑移除了某些加密算法和 DH 参数。--ignore-ssl 会放宽校验和协议约束,但无法找回已从二进制文件中移除的加密套件(RC4、3DES、弱 DH)。变通方案:使用较老的 curl、终止 TLS 的代理,或重新编译 OpenSSL。
代理¶
--proxy 被忽略¶
显式的 -x/--proxy 参数始终优先于环境变量。请检查:
- 你没有误传空字符串——
--proxy ""会**显式禁用**基于环境变量的代理并强制直连。 - 协议方案与目标匹配——
HTTPS_PROXY用于https://URL,HTTP_PROXY用于http://。 - 目标主机未被
NO_PROXY匹配。检查 JSON 导出中的proxy_source字段;如果它显示NO_PROXY,说明你的主机被排除了。
Invalid proxy URL¶
格式错误的 -x/--proxy 值(不支持的协议、缺少主机、端口无效或超出范围、未闭合的 IPv6 字面量)会在发出任何请求之前以退出码 64 被拒绝。如果 HTTP_PROXY、HTTPS_PROXY 或 ALL_PROXY 存在同样的问题,请求会以指出该变量的网络错误(退出码 75)失败。两种错误显示的 URL 都会遮蔽密码。不带协议的值(如 proxy.local:3128)是有效的,会被视为 http://。
NO_PROXY 模式参考¶
- 主机及其子域名:
api.internal.example(也匹配v1.api.internal.example) - 仅子域名:
.internal.example(匹配foo.internal.example,不匹配internal.example) - 通配符:
*(排除一切) - 多个条目:逗号分隔,去除首尾空白,不区分大小写
IP 地址按普通主机名进行比较。**不**支持 CIDR 范围(curl 自 7.86.0 起支持)和带端口的条目。
HTTP/2¶
即使未传 --no-http2,服务器仍以 HTTP/1.1 响应¶
HTTP/2 需要在 TLS 握手期间进行 ALPN 协商。如果:
- 服务器未在 ALPN 中通告
h2,或 - 目标使用纯
http://(不支持 h2c),
httptap 会回退到 HTTP/1.1。请检查 JSON 导出中的 network.http_version。
如何强制使用 HTTP/1.1?¶
使用 --no-http2(兼容 curl 的别名 --http1.1)。这会完全禁用 ALPN h2 协商。
计时¶
timing.is_estimated: true —— 这是什么意思?¶
httptap 通常从 httpcore 的 trace 钩子获取各阶段计时。当这些钩子没有为某个请求报告任何连接/TLS 事件时(例如某个不发出 httpcore trace 事件的传输层),httptap 会回退到用启发式方法拆分 DNS 与首个响应字节之间的时间(HTTPS 下为 30% 连接、70% TLS)。这样的分解在方向上仍然正确,但不如默认路径精确。
为什么连续两次运行显示的 dns_ms 差异巨大?¶
系统解析器会缓存条目。第一次请求要支付到你 DNS 服务器的完整 RTT;后续请求则命中缓存(往往是亚毫秒级)。若要绕过缓存,请通过 Python API 提供自定义解析器,或刷新本地缓存(例如 macOS 上的 sudo dscacheutil -flushcache,systemd 上的 resolvectl flush-caches)。
connect_ms 远高于往返时间¶
当主机解析出多个地址时,httptap 会按顺序尝试,连接失败时转到下一个地址。失败尝试所花的时间会计入 connect_ms 和 total_ms(与 curl 的 time_connect 相同),而 ip 显示的是实际响应的地址。使用 --resolve 可以只测量单个地址。
每个重定向步骤都显示完整的 connect_ms 和 tls_ms¶
httptap 会为每个请求(包括每个重定向步骤)打开一个新连接,因此连接从不复用,每个步骤都要各自完成 TCP 连接和 TLS 握手。ttfb_ms 从 DNS 解析开始时计起,因此它已经包含了 dns_ms、connect_ms 和 tls_ms;服务器自身的处理时间是 wait_ms。如果某个步骤的计时全部为 0,说明它在收到响应之前就已失败——请检查其 error 字段。
输出¶
我的终端没有颜色¶
httptap 遵循 NO_COLOR 约定和 Rich 的 TTY 检测:
- 若设置了
NO_COLOR,请取消设置。 - 将 stdout 管道到文件或另一个进程会禁用颜色;设置
FORCE_COLOR=1可覆盖。 TERM=dumb同样会禁用渲染。
--metrics-only 不再显示 proxy= 字段¶
它并没有——该字段在每个收到响应的步骤中都存在。旧的截图/示例可能早于该变更。失败的步骤会输出为 Step N: ERROR - <message>,不包含指标和 proxy= 字段。成功步骤的预期格式:
可能的取值:
proxy=<url> proxy_from=arg—— 通过-x/--proxy设置的代理。proxy=<url> proxy_from=env:<VAR>—— 取自https_proxy或HTTPS_PROXY等环境变量的代理。proxy=none proxy_from=env:no_proxy—— 主机命中了NO_PROXY。proxy=disabled proxy_from=arg—— 通过--proxy ""禁用了代理。proxy=direct proxy_from=no_scheme_match—— 设置了代理变量,但没有一个适用于该 URL 的协议方案。proxy=direct—— 未配置代理。
如果某些值会破坏 key=value 的分词,则会对其进行百分号编码。
脚本化与 CI¶
我应该检查哪些退出码?¶
参见 README 中的 Exit Codes 部分。典型的 CI 模式:将 75(网络 / TLS,瞬时)视为可重试,遇到 64(用法)、70(缺陷)、47(使用 --follow 时达到重定向上限)、73(未能写入 --json 或 --har 文件)、22(使用 --fail 时收到 HTTP 4xx/5xx)和 4(若你提供了 --slo 的 SLO 违规)则直接失败。当多个条件同时满足时,优先级最高的退出码胜出;参见优先级表。
即使请求很慢,我的 --slo 预算却从不触发。¶
请检查三件事:
- 你设置的键映射到一个真实存在的计时阶段。有效的键是
dns、connect、tls、ttfb、wait、xfer、total——其他任何值都会以退出码64(SLO Error 面板)拒绝该命令。 - SLO 是在**最终成功的步骤**上评估的,而非中间的重定向。如果
--follow经过了若干跳,而最后一步很快,那么整个链的总时间不会被比较。请用total对照最后一个请求的预算,或在需要逐步保证时从--json手动聚合。达到重定向上限时,被评估的步骤是最后一个3xx响应。 - 如果每一步都出错,SLO 会被完全跳过——退出码反映的是网络故障(通常是
75)。此时--metrics-only输出中不会出现slo=标记。
httptap 能输出 Prometheus 指标吗?¶
可以。使用 --prometheus PATH 写出 node_exporter textfile collector 文件。指标名称和标签参见输出格式。
Python API¶
ImportError: cannot import name 'HTTPMethod' from 'httptap'¶
HTTPMethod 位于 httptap.constants,而非顶层命名空间:
我的自定义解析器没有被调用¶
HTTPTapAnalyzer 会在直连和本地 DNS 解析的 SOCKS5 代理中使用注入的解析器。HTTP、HTTPS 和 SOCKS5H 代理会在远端解析目标主机;如需改变这一行为,请使用自定义的 RequestExecutor。
仍未解决?¶
- 使用
--metrics-only运行,并在你的报告中包含完整输出。 - 使用
--json report.json运行并附上该报告(请脱敏认证请求头)。 - 确认版本——
httptap --version——我们仅支持最新的次要版本。