第 2 章 网络请求基础:HTTP/HTTPS 协议原理、请求与响应结构、状态码详解
大家好,我是你们的老朋友。今天咱们聊聊网络请求最底层的东西——HTTP 和 HTTPS。很多人觉得这东西太基础,不就是个 URL 嘛,发出去等返回就行了。但我在 SDK 优化里踩过的坑,基本都是因为这些基础没吃透。你想想,一次网络请求从发起到结束,中间有多少环节?DNS 解析、连接建立、数据传输、连接关闭,每个环节都可能成为瓶颈。
我自己有个习惯:碰到线上问题,先抓包看原始请求和响应。很多时候问题就出在请求结构不对,或者状态码理解偏了。今天把这部分彻底理清楚,后面讲流量优化才有底。
HTTP 协议的本质与演化
HTTP 说白了就是客户端和服务器之间约定的对话格式。你发什么内容,对方按什么结构回复,全靠这个协议来约束。
目前主流版本就三个:HTTP/1.1、HTTP/2、HTTP/3。它们的主要区别我列个表:
| 版本 | 连接模型 | 多路复用 | 头部压缩 | 传输层 |
|---|---|---|---|---|
| HTTP/1.1 | 串行队列 + 持久连接 | 不支持 | 无 | TCP |
| HTTP/2 | 二进制分帧 | 支持 | HPACK | TCP |
| HTTP/3 | 无队头阻塞 | 支持 | QPACK | QUIC (UDP) |
我记得前两年做一个 SDK,用户量上来后 HTTP/1.1 的队头阻塞把请求延迟推到 2 秒以上。后来切到 HTTP/2,用同一个连接发送多个请求,延迟直接降了 40%。这个教训让我意识到:协议版本选对了,就是免费的优化。
注意: 虽然 HTTP/2 支持多路复用,但很多 CDN 和反向代理在实现上仍然会对同一个域名的连接数做限制。我曾经遇到过一个案例,客户端开了 6 个 HTTP/2 连接,结果服务器端直接限流了。最好的做法是用单个长连接,配合优先级控制。
HTTPS 的加密握手与证书校验
HTTPS 本质上是 HTTP over TLS。它解决了三个问题:加密传输、数据完整性、身份认证。我见过不少开发者只关心 HTTPS 开启没开启,却忽略了握手阶段的开销。
TLS 握手流程大致如下:
- 客户端发起
ClientHello,附带支持的加密套件、TLS 版本、随机数。 - 服务器回复
ServerHello,选定加密套件,附带证书链和服务器随机数。 - 客户端验证证书,生成预主密钥,用服务器公钥加密后发送。
- 服务器解密得到预主密钥,双方各自计算出会话密钥。
- 发送
ChangeCipherSpec,之后所有数据加密传输。
这里有个点常被忽略:证书链的长度。我之前在某大厂 SDK 里发现,一个 API 的证书链包含 4 个中间证书,每次握手光证书验证就要多花 200ms。后来让服务端做 OCSP Stapling,把证书状态信息提前缓存了,问题才解决。
建议: 在 SDK 里尽量复用 TLS 会话。开启 Session ID 或 Session Ticket 机制,可以让重连时跳过完整的握手,省掉一次 RTT。我一般会在客户端缓存 2~3 个工单状态的会话票据。
请求与响应的结构
HTTP 请求和响应的格式其实非常清晰,我给大家拆开看:
请求结构
GET /api/v1/user HTTP/1.1
Host: example.com
User-Agent: SDKClient/1.0
Accept: application/json
Authorization: Bearer xyz
(请求体,GET 通常为空)
请求行包含 方法 + 路径 + 协议版本。头部字段每行一个,用冒号分隔。空行之后是请求体。我见过很多 SDK 的坑是:头部字段的顺序在不同 HTTP 库里不一致,导致某些后端解析失败。尤其是 Host 字段,HTTP/1.1 必须带上,否则服务器会返回 400。
响应结构
HTTP/1.1 200 OK
Date: Mon, 10 Mar 2025 12:00:00 GMT
Content-Type: application/json
Content-Length: 128
{"status":"ok","data":{...}}
响应行:协议版本 + 状态码 + 原因短语。后面跟头部和空行,最后是响应体。注意:Content-Length 和 Transfer-Encoding: chunked 是互斥的,不能同时出现。我踩过这个坑——后端同时返回了这两个头,SDK 的解析库直接崩溃。
状态码详解
状态码是服务器对请求结果的「一句话总结」。我习惯把它们按类别记忆:
- 1xx 信息性:比如
101 Switching Protocols,用在 WebSocket 升级时。 - 2xx 成功:
200 OK常见,204 No Content表示请求成功但没有响应体,206 Partial Content用于断点续传。 - 3xx 重定向:
301 Moved Permanently和302 Found是最常见的。我建议默认不自动跟随,因为有些 SDK 内部重定向逻辑会泄露 authorization 头。 - 4xx 客户端错误:
400 Bad Request(参数问题)、401 Unauthorized、403 Forbidden、404 Not Found、429 Too Many Requests(限流)。 - 5xx 服务端错误:
500 Internal Server Error、502 Bad Gateway、503 Service Unavailable、504 Gateway Timeout。
做 SDK 时,状态码的异常处理要特别细致。我见过一个 SDK 遇到 429 不做退避,结果被网关封 IP。好的做法是:4xx 多数不重试,5xx 可以带指数退避重试,但要限制次数。
避坑指南: 我曾经因为没处理 302 重定向,导致用户数据被发送到第三方服务器。后来我在 SDK 里强制检查 Location 字段的 host 是否在白名单内,不在就报错。
核心流程图:HTTP/HTTPS 请求生命周期
下面这张图我把完整流程画出来,重点标注了 HTTPS 和 HTTP/2 的差异点。你可以看到,一次请求背后有多少握手和头部交互。
这张图里我特意标出 HTTPS 要比 HTTP 多一次 TLS 握手。你想想,多一个 RTT 在一些弱网环境里可能就是几百毫秒。所以业界搞出了 TLS 1.3、0-RTT 技术,就是想要省掉这一轮。
OK,这一章的核心知识点就这些。记住:请求结构对了,状态码懂了,握手流程熟了,你做 SDK 的时候就能一眼看出问题出在哪个环节。后面我们还会反复用到这些基础。