一次请求慢,不能只看总耗时就断言是 TLS、目标服务器或代理服务商的问题。对一条全新的、成功的 HTTP/1.1 GET,curl 可以给出四个累计时刻;相邻相减后,才能得到四段不重叠的观察区间,再做受控比较。
本文面向已经运行获准代理任务、需要为续用或排障保留证据的工程人员。它只拆解单次传输,不测应用排队、重试退避、解析、curl 之外的 DNS,或完整用户流程;更不能据此给任何网络或服务商定责。
先收集范围明确的样本
选择自有或已获许可的无副作用目标。每条样本单独启动一个 curl 进程且只给一个 URL,只做一次 HTTP/1.1 GET:不上传、不跟随重定向、不重试、不接收 1xx。检查保存的响应头,确认没有信息响应。组内保持客户端主机、代理端点、目标、请求头、负载大小、并发、地区和会话模式相同。连接复用后,时间含义已经不同。
# PROXY_CONFIG 是本机权限受限的 curl 配置文件,禁止提交。
# 文件只保存已批准的代理端点/认证配置。
curl -q --config "$PROXY_CONFIG" --http1.1 --max-redirs 0 --retry 0 --max-time 30 \
--dump-header response.headers --output response.body --silent --show-error \
--write-out '{"curl_exit":%{exitcode},"http_status":"%{response_code}","connect":%{time_connect},"pretransfer":%{time_pretransfer},"starttransfer":%{time_starttransfer},"total":%{time_total}}\n' \
'https://test.example/health'
-q 必须放在第一个参数,避免 curl 加载默认 curlrc。该本机配置文件不能再添加 URL、上传、重试、重定向、write-out 格式或其他破坏本测试边界的行为。--max-time 30 只是本次测试上限,不是产品速度目标。不要把凭据写进进程参数、shell 历史或输出。%{exitcode} 要求 curl 7.75.0 或更新版本。三位状态码故意加引号,确保 curl 的 000 仍是有效 JSON。每行还应保存退出码、HTTP 状态、时间戳、curl 版本、客户端地区、已去密的代理产品/端点标识、目标类别、测试配置和响应字节数。每个样本使用独立目录保存 response.body/response.headers,避免后续样本覆盖证据。先保存并验证正文,检查响应头有无信息响应,再设为 content_valid:true;只有该标记为真、curl exit 为 0 且响应为 2xx,才可进入本拆解。比如 curl exit 28 超时,应带着 curl 已输出的原始时间保留为失败行;原始值会保留,但不作为已验证的拆分数据;没有得到的阶段不能填成零。
把累计时刻变成四段区间
curl 官方定义:time_connect 从开始到远端主机或代理连接完成,因此可能包含 DNS 等此前工作,不能视为纯 TCP;time_pretransfer 包含协议相关的传输前命令和协商;time_starttransfer 到 libcurl 收到响应首字节,通常是响应头;time_total 是整次传输。它们都是从开始累计,所以应报告:
connect_ms = connect * 1000
post_connect_setup_ms = (pretransfer - connect) * 1000
wait_first_byte = (starttransfer - pretransfer) * 1000
after_first_byte = (total - starttransfer) * 1000
若原始秒数为 [.08, .32, .62, .82],四段就是80 / 240 / 300 / 200 ms,相加回到 820 ms,没有重复计算。
| 区间 | 包含什么 | 不能直接称为 |
|---|---|---|
| connect | 连接到远端主机或代理完成。 | 只有“代理延迟”或只有 TCP 质量。 |
| post-connect setup | 连接后协议准备,可能含代理 CONNECT、TLS 和其他协商。 | 纯 TLS 时间。 |
| wait-first-byte | 传输开始到首字节;网络与服务端工作都可能参与。 | 纯服务端 CPU 时间。 |
| after-first-byte | 首字节后的剩余响应,含余下响应头与正文传输,受大小、传输路径和客户端写入影响。 | 服务商吞吐承诺。 |
使用离线分析器,不发送任何请求
下载标准库分析器。不带文件运行时,只输出明确标注的合成样例,不会连接网络。
python3 proxy-latency-breakdown.py --self-test
python3 proxy-latency-breakdown.py
真实记录使用严格 JSON。工具会拒绝负数、NaN、缺失时刻、非单调时刻、复用连接和重定向,也会拒绝重复 ID 以便追溯。失败行可以保留 curl 已输出的原始时间,但工具不会为它伪造区间。工具只核验你的声明,不能证明实际流量符合范围;应检查保存的响应头有无 1xx,并保留命令和配置证据。
{
"scope": {"connection":"new","http_version":"1.1","method":"GET","follow_redirects":false,"retries":0,"upload":false,"allow_1xx":false},
"observations": [
{"id":"sample-17","curl_exit":0,"http_status":"200","content_valid":true,"connect":0.08,"pretransfer":0.32,"starttransfer":0.62,"total":0.82},
{"id":"timeout-18","curl_exit":28,"http_status":"000","content_valid":false,"total":20.0}
]
}
将上方 JSON 保存为 observations.json。处理自己的测量时,把每次 curl 输出对象放入 observations,补上唯一 id 与正文验收结果 content_valid,再声明已核对的采集范围。原始记录另行保留,然后执行:
python3 proxy-latency-breakdown.py observations.json
工具自带的合成样例分别隔离较长准备段 [.08,1.52,1.82,2.02]、等待首字节段 [.08,.32,2.12,2.32] 和首字节后剩余响应段 [.08,.32,.62,2.42]。它们只是教学输入,不是 IPHTML 的实测。
用受控实验决定下一步
| 反复出现的变化 | 下一项受控检查 | 决策边界 |
|---|---|---|
| connect 变长 | 从第二个已批准的客户端网络,对同一目标和代理端点比较。 | 应用排队/重试要单独计时;单一路径不能定责。 |
| 连接后准备变长 | 核对代理协议、认证模式与新连接;只在适当时做获准的直连基准。 | 不能直接叫 TLS 问题,也不要无证据改凭据。 |
| 等首字节变长 | 固定 URL、请求头、正文和并发;若有权限,查看目标侧遥测。 | 它可能同时含网络和服务端工作。 |
| 首字节后剩余响应变长 | 记录响应字节数和客户端读取行为,比较同样大小的响应。 | 不能把更大的响应当成代理网关基准。 |
在改变付费配置前,应跨有意义时段积累可比较的样本。一快一慢只说明那两次传输。完整任务的截止时间、失败与重试恢复,应另用可靠性记分表衡量;本文只拆一条传输。若任务要在多次请求中保持连续状态,另用代理会话验收指南测试,不能把一次连接的耗时当作会话保证。
可发给支持方的脱敏记录模板
窗口/时区:[实际起止时间及 UTC 偏移]
范围:新 HTTP/1.1 GET;无重定向/重试/上传/1xx;curl 版本:
目标类别及授权:[去敏类别]
代理端点/产品:[主机或套餐标识,不含凭据]
组内控制:客户端地区、并发、请求头、响应字节、会话模式
记录:id、curl exit、HTTP 状态、connect/post-connect-setup/wait-first-byte/after-first-byte 四段
比较:基准组与唯一改变的变量
问题:哪项已文档化的配置或安全下一步测试,能区分该区间变化?
删除代理密码、Cookie、认证头、个人资料和敏感 URL 参数。若证据指向获准长期任务的配置问题,可先查看 轮换代理入口,再通过IPHTML 联系入口提交记录。请核对具体套餐当前配置;本文不承诺时延、可用性、价格或支持响应时间。
方法说明:2026 年 10 月 12 日依据 curl 官方 CONNECT_TIME、PRETRANSFER_TIME、STARTTRANSFER_TIME、TOTAL_TIME 与 write-out 核对术语。离线工具已完成自测;没有进行付费代理或 IPHTML 性能实测。