欢迎光临
我们一直在努力

网站打开慢?用curl定位请求耗时

网站打开慢,问题可能出在域名解析、网络连接、HTTPS 握手,也可能是网站程序迟迟没有返回内容。

如果没有先确定慢在哪个阶段,就直接增加带宽、升级服务器或修改缓存设置,往往很难判断改动是否有效。

本文介绍一种实用的排查方法:使用 curl 输出一次请求的各项耗时,先找到值得继续检查的阶段,再结合服务器日志和浏览器工具定位原因。

1. 先明确:curl 测的是一次请求

浏览器打开一个网页,通常需要请求 HTML、CSS、JavaScript、图片和接口数据,还要执行脚本并完成页面渲染。

而本文的 curl 命令,只请求指定的一个 URL。

例如,测试网站首页时,curl 会获取首页返回的内容,但不会像浏览器一样继续下载 HTML 中引用的全部图片和脚本。

因此,测试之前先确定目标:

  • 首页迟迟没有响应,先测首页 URL。
  • 某个接口很慢,测对应的接口 URL。
  • 图片下载慢,测具体图片地址。
  • 页面内容已经出现,但操作仍然卡顿,需要进一步检查前端执行和渲染。

建议先选择自己网站中一个无需登录、没有写入操作的公开页面。

另外,测试位置也要一致。服务器访问自身的结果,不能直接代表用户从家庭宽带或移动网络访问时的体验。

2. 用 curl 输出一次请求的耗时

2.1 检查是否安装 curl

以下命令适用于 Linux、macOS 或 Windows WSL 中的终端。

先执行:

curl --version

如果 Debian 或 Ubuntu 提示找不到命令,可以安装:

sudo apt-get update
sudo apt-get install -y curl ca-certificates

使用 root 用户时,可以去掉命令前面的 sudo。

2.2 执行耗时测试

将下面的 https://www.example.com/ 替换为自己要检查的实际 HTTPS 地址:

curl -q --http1.1 \
  --connect-timeout 10 \
  --max-time 30 \
  -sS -o /dev/null \
  -w 'HTTP=%{http_code}\nIP=%{remote_ip}\nDNS=%{time_namelookup}s\nTCP_DONE=%{time_connect}s\nTLS_DONE=%{time_appconnect}s\nREADY=%{time_pretransfer}s\nFIRST_BYTE=%{time_starttransfer}s\nTOTAL=%{time_total}s\n' \
  'https://www.example.com/'

这里使用 -w 在请求结束后输出指定字段,-o /dev/null 丢弃响应内容,因此终端主要显示状态码、连接 IP 和耗时。响应内容仍然会被下载,只是不保存到文件。

命令设置了 10 秒连接超时和 30 秒总超时,避免异常请求一直等待。

为便于比较,本文统一使用 HTTP/1.1。浏览器可能使用 HTTP/2 或 HTTP/3,因此两者结果可能不同。

另外,-q 用于跳过默认 curl 配置文件,但不会清除终端中的代理环境变量。如果终端配置了 HTTP 或 HTTPS 代理,需要把代理路径也考虑进去。

3. 看懂这六个时间:它们是累计值

这是使用 curl 分析耗时最容易弄错的地方:

这些字段大多表示“从请求开始,到某个阶段完成”的累计时间,不能直接相加。

输出名称对应字段表示什么
DNStime_namelookup从开始到域名解析完成
TCP_DONEtime_connect从开始到 TCP 连接完成
TLS_DONEtime_appconnect从开始到 TLS 握手完成
READYtime_pretransfer从开始到准备开始传输
FIRST_BYTEtime_starttransfer从开始到收到响应首字节
TOTALtime_total本次操作的总耗时

这些字段的单位都是秒。对于本文这种单次 HTTPS 请求,判断某一阶段的耗时,需要看相邻时间点的差值。

例如:

TCP_DONE=0.045s 不代表 TCP 建连单独花了 45 毫秒,因为这个累计时间中还包含前面的域名解析过程。

同样,FIRST_BYTE=1.291s 也不能直接理解成网站程序执行了 1.291 秒。

下面的差值分析,适用于请求成功、直连目标、没有跳转、没有连接复用的单次 HTTPS 请求。如果使用代理、跟随多次跳转,或者请求发生错误,就不能直接照搬。

curl的DNS、TCP、TLS、首字节与总耗时累计值示意

4. 用一组示例,计算慢在哪个阶段

假设得到以下结果。

这是一组用于说明计算方法的示例数据,不是某个网站的实测结果。

HTTP=200
IP=203.0.113.10
DNS=0.015000s
TCP_DONE=0.045000s
TLS_DONE=0.090000s
READY=0.091000s
FIRST_BYTE=1.291000s
TOTAL=1.351000s

先把累计时间换算成毫秒,再计算差值:

阶段计算方式示例结果
DNS 解析DNS15 毫秒
TCP 建连相关区间TCP_DONE − DNS30 毫秒
TLS 握手相关区间TLS_DONE − TCP_DONE45 毫秒
准备传输后到收到首字节FIRST_BYTE − READY1200 毫秒
首字节后到请求完成TOTAL − FIRST_BYTE60 毫秒

从这组数据看,最值得继续检查的是:

连接和握手完成后,到收到首字节之间的等待。

但这 1200 毫秒仍不能直接等同于“程序执行时间”。该区间还可能包含请求发送、网络往返、代理转发、服务端排队及处理等因素。curl 的首字节时间本身也包含前面的连接准备时间。

正确的下一步,是记录测试时间和 URL,然后对照反向代理、应用及数据库日志,继续查找等待发生在哪里。

5. 根据耗时选择下一步排查方向

根据curl请求耗时排查网站访问慢的原因

有了时间分布后,可以按下面的方向继续检查:

观察到的现象优先检查什么
DNS 解析耗时反复偏高当前解析器、解析缓存、DNS 请求是否异常
TCP 建连区间偏长网络路径、连接重试、目标端口及服务连接压力
TLS 握手区间偏长网络往返、TLS 握手情况及相关服务日志
准备传输后等待首字节很久应用处理、数据库查询、反向代理、CDN 回源与缓存情况
首字节很快,但请求结束很晚响应体大小、传输速率、服务端是否持续分段输出
curl 很快,浏览器仍然慢图片、脚本、接口请求以及前端执行和渲染

这张表用于确定排查方向,不能仅凭某一项数值就认定故障原因。

例如,等待首字节较久,可能与数据库慢查询有关,也可能是 CDN 没有命中缓存,需要等待源站返回。

首字节后的耗时较长,也不一定就是带宽不足。响应体较大、服务端分批生成内容,都会拉长这段时间。

如果网站已经接入 CDN,IP 显示的通常是本次实际连接的节点地址,不能直接当成源站 IP;使用代理时,还可能显示代理地址。

需要对照测试新服务器或指定源站时,可以参考本站文章:网站迁移前如何测试新服务器。使用域名配合指定解析测试,可以保留正常的主机名和 HTTPS 证书校验条件。

6. 不要只测一次,也不要忽略状态码

6.1 连续测试,观察是否稳定

一次请求可能恰好遇到网络波动、缓存未命中或临时负载。

可以连续测试 5 次,每次间隔 1 秒:

for i in 1 2 3 4 5; do
  curl -q --http1.1 \
    --connect-timeout 10 \
    --max-time 30 \
    -sS -o /dev/null \
    -w "第${i}次 HTTP=%{http_code} IP=%{remote_ip} 首字节=%{time_starttransfer}s 总耗时=%{time_total}s\n" \
    'https://www.example.com/'
  sleep 1
done

同样需要替换为自己网站的实际地址。

重点观察:

  • 是否每次都慢,还是偶尔出现一次明显偏高。
  • 状态码是否一致。
  • 实际连接的 IP 是否变化。
  • 首次访问与后续访问是否有明显差异。

这只是少量请求的排查,不是压力测试。重复执行也不会自动清空系统 DNS 缓存或 CDN 缓存。

6.2 先确认返回的是正常页面

响应很快,并不代表访问正常。

例如:

  • 返回 301 或 302,可能只测到了跳转响应。
  • 返回 403,可能拿到的是访问拒绝页面。
  • 返回 404,可能测试地址写错了。
  • 返回 502,需要先处理网关或上游服务异常。
  • 显示 000,表示没有取得 HTTP 状态码,应先查看 curl 输出的错误信息。

本文的主命令没有添加 -L,因此不会自动跟随跳转。

如果发现返回 301 或 302,可以查看响应头:

curl -q --http1.1 \
  --connect-timeout 10 \
  --max-time 30 \
  -sS -D - -o /dev/null \
  'https://www.example.com/'

找到 Location 指向的目标,确认最终访问地址后,再对最终 URL 执行前面的耗时测试。

这样能避免把多个请求的时间混在一起分析。跟随跳转时,curl 的相关累计耗时会受到前面请求的影响。

如果返回的是 502 Bad Gateway,可以继续参考本站:Nginx出现502 Bad Gateway怎么办?常见原因与排查教程。

7. curl 很快,为什么浏览器还是慢?

如果首页的 curl 请求很快,但浏览器依然需要很久才能显示完整页面,接下来应检查页面中的其他资源。

以 Chrome 为例:

  1. 打开开发者工具,进入 Network(网络)。
  2. 保持开发者工具打开,勾选 Disable cache(停用缓存)。
  3. 重新加载页面。
  4. 先查看页面文档请求,再检查图片、JavaScript 和接口请求。
  5. 点击耗时较长的请求,在 Timing(时间) 中查看具体阶段。

Chrome 的 Network 面板可以记录页面请求,并进一步显示单个请求的等待与下载等时间。

常见情况包括:

  • HTML 返回很快,但页面引用的图片体积过大。
  • 页面必须等待某个接口返回后,才能显示主要内容。
  • 第三方脚本或外部资源响应较慢。
  • 网络请求已经结束,浏览器仍在执行脚本或渲染页面。

如果主要时间花在脚本执行和渲染上,就需要继续查看 Performance(性能)面板。

对照 curl 和浏览器结果时,还要留意 Cookie、登录状态、缓存、HTTP 版本及请求头是否一致。两个请求条件不同,耗时就不能简单地直接比较。

8. 结尾:先找到慢的阶段,再决定怎么优化

排查网站打开慢,可以先从一个具体 URL 开始,使用 curl 查看 DNS、连接、TLS、首字节和总耗时,再根据时间差值缩小检查范围。

其中最需要记住的是:累计时间不能相加,首字节耗时不等于程序执行时间,一次 URL 请求也不等于整个网页的加载过程。

当你能明确说出“慢在解析”“慢在建立连接”或“连接后等待响应较久”,后续检查日志、调整缓存和优化程序就会更有方向,也更容易验证改动是否有效。

赞(0)
未经允许不得转载:莱卡云 » 网站打开慢?用curl定位请求耗时