一条 curl 命令判断页面打不开是网络问题还是服务问题
页面打不开时,第一反应往往是“网有问题”或“服务器挂了”。这两种判断差别很大:前者查链路,后者查服务。一条 curl 命令能同时给出两边的线索。
什么情况下用得上
浏览器里某个地址转圈很久或直接报错,但说不清卡在哪一环,又不想开抓包工具或开发者工具。此时只需确认三件事:对方有没有回话、回的是什么状态、花了多长时间。curl -I 只请求响应头,不下载正文,适合快速探测。
命令在做什么
curl -I -L -w '%{http_code} %{time_total}\n' -o /dev/null https://example.com/
-I发 HEAD 请求,只要响应头。-L跟随重定向。不加它,遇到 301/302 就停在第一跳,看不到最终状态。-w '%{http_code} %{time_total}'在末尾追加最终状态码和总耗时(秒)。-o /dev/null丢弃响应头正文,终端只剩-w那一行。
输出先是若干行 HTTP/1.1 200 OK,最后一行是 200 0.842。
怎么读这两个数
状态码:2xx 服务正常应答;3xx 还在跳转,配合 -L 应落到 2xx;4xx 多半是路径、权限或参数问题,服务本身活着;5xx 是服务端出错;完全没有状态码、只有 curl: (…) 报错,说明 TCP 连接或 TLS 握手都没完成。
耗时:time_total 一秒以内通常正常。注意 -I 只取头,正文几乎为零,所以耗时基本反映建连、TLS 握手和首字节等待,不含下载时间。
| 状态码 | 耗时 | 判断 |
|---|---|---|
| 2xx | 短 | 链路和服务都正常,问题可能在浏览器侧 |
| 2xx | 长 | 服务能应答但慢,查后端处理或首字节延迟 |
| 5xx | 任意 | 服务活着但内部出错,查服务日志 |
| 4xx | 短 | 请求本身有问题,地址或鉴权不对 |
| 无 | 长或超时 | 网络层问题,DNS、路由或防火墙 |
分步确认
第一步,先跑一次不带 -L 的命令看第一跳。若第一跳是 301,说明有重定向,加 -L 再看最终落点。
第二步,把耗时拆开:
curl -I -L -o /dev/null -w 'dns=%{time_namelookup} conn=%{time_connect} tls=%{time_appconnect} first=%{time_starttransfer} total=%{time_total}\n' https://example.com/
哪一段明显偏大,问题就在哪一段。DNS 慢查解析配置,连接慢查路由和防火墙,TLS 慢查证书链,首字节慢多半是服务端在排队。
第三步,换一个已知正常的地址做对照。对照地址快、目标地址慢,问题在目标侧;两个都慢,问题在本机网络出口。
怎么判断哪一步失败
只有 curl: 开头的错误行、没有状态码,说明请求没走完。Could not resolve host 是 DNS 失败,Connection timed out 是 TCP 连不上,SSL certificate problem 是证书校验没过——都属于网络或配置层,不是服务逻辑故障。反过来,只要有状态码输出,连接就已建立、对方应用层回了话,剩下的是解读状态码。
边界与代价
-I 发的是 HEAD 请求,少数服务对 HEAD 的实现和 GET 不一致,可能返回 405 或与真实页面不同的状态码。要更贴近真实访问,把 -I 换成 GET 配合 -o /dev/null,代价是会实际传输正文。
单次耗时受瞬时波动影响,判断“慢”之前建议连跑两三次。-L 跟随重定向时,time_total 是整条跳转链的累计值,跳转多时会偏大,需结合每一跳的状态码分别看。
这条命令只测一个地址的一次请求,适合快速分诊,不能替代对整条链路的持续监控。