969 字
5 分钟
HTTP 与 HTTPS:TLS 握手、证书链与 curl 调试技巧

curl -v 输出的每一行都对应协议栈里的一个阶段。学会读它,HTTP/HTTPS 问题就排掉了一半。本文以一次真实请求为样本,讲清 HTTP 报文结构、TLS 握手在干什么、证书报错怎么定位。

一次请求的完整解剖#

Terminal window
curl -v https://example.com/

> 开头是客户端发出的,> 之外带 < 的是收到的,* 是 curl 自己的注释。发出部分:

GET / HTTP/2
Host: example.com
User-Agent: curl/8.x
Accept: */*

这就是 HTTP 请求报文的全部骨架:请求行(方法 + 路径 + 版本)+ 首部(键值对)+ 可选的请求体。响应同理:状态行(HTTP/2 200)+ 首部 + 正文。

要单独看首部用 curl -I(发 HEAD 请求);要忽略正文只看交换过程用 curl -sv https://... -o /dev/null。

TLS 握手在 HTTP 之前#

curl -v 里 * 部分有一段 TLS 日志:

* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384

握手的两个目标:协商加密参数和验证服务器身份。

  • TLS 1.2:密钥协商走 RSA 或 ECDHE,需要两个完整往返(2-RTT)。
  • TLS 1.3(2018 年定稿,现为主流):客户端在 Client Hello 里直接带上密钥材料,1-RTT 完成握手,且支持 0-RTT 会话恢复;同时把证书之后的握手消息也加了密。

对使用者来说结论很简单:TLS 1.3 更快更安全,服务端应优先启用并保留 1.2 兜底,1.0/1.1 必须禁用。

证书链:浏览器凭什么信任这个网站#

服务器在握手中出示的不是一张证书,而是一条链:

服务器证书(example.com)
↑ 由 中间 CA(如 R3)签发
↑ 由 根 CA(如 ISRG Root X1)签发 ← 预置在操作系统/浏览器信任库

验证逻辑:逐级用上级公钥校验签名,直到碰到信任库里已有的根。中间证书必须由服务器一起下发——最常见的「浏览器正常、curl/旧安卓报证书错误」,就是服务器漏配中间证书(fullchain),浏览器能自动补齐而别的客户端不能。

用 OpenSSL 查看证书细节:

Terminal window
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates

-dates 看有效期(过期是第二大常见故障),-servername 用于一台服务器托管多个 HTTPS 站点(SNI)时指定域名。

常见证书报错对号入座#

curl 报错含义处理
certificate has expired证书过期续期,检查自动续期任务是否失效
unable to get local issuer certificate服务器没发中间证书,或本地 CA 库太旧服务端配置 fullchain;客户端更新 ca-certificates
subject name mismatch证书域名与访问域名不符证书上 SAN 没包含该域名(注意 www. 前缀差异)
self signed certificate自签名证书内网可 -k 跳过或分发 CA;公网换正规证书

把请求拆开计时#

接口慢,到底是 DNS 慢、握手慢还是服务器处理慢?

Terminal window
curl -so /dev/null -w 'DNS:%{time_namelookup}s TCP:%{time_connect}s TLS:%{time_appconnect}s 首字节:%{time_starttransfer}s 总:%{time_total}s\n' https://example.com/
  • time_connect - time_namelookup ≈ TCP 握手耗时(约等于 RTT);
  • time_appconnect - time_connect ≈ TLS 握手耗时;
  • time_starttransfer - time_appconnect ≈ 服务器处理并返回首字节的耗时。

一眼就能看出慢在哪一段,比凭感觉猜高效得多。

HTTP/2 与 HTTP/3 简述#

HTTP/2 在单条 TCP 连接上多路复用(解决 HTTP/1.1 队头阻塞),首部走 HPACK 压缩;HTTP/3 把底层换成基于 UDP 的 QUIC,进一步消除 TCP 层队头阻塞并改善弱网切换。对开发者透明——curl 和浏览器会自动协商(curl -v 里能看到 ALPN: server accepted h2),服务端用 Nginx/云 CDN 开启即可。

延伸阅读#

HTTP 与 HTTPS:TLS 握手、证书链与 curl 调试技巧
https://meow.us.kg/posts/http-https-tls-curl-debug/
作者
もゆちゃん
发布于
2026-09-21
许可协议
CC BY-NC-SA 4.0

分享文章

生成精美分享图或复制链接,与更多人分享本文。

继续阅读

沿着主题读

基于共同的标签与分类

换条路线

从其他文章中稳定抽取