报文就是纯文本
HTTP/1.1 的报文人眼直接可读,这是它最大的优点也是最大的债。一个请求加响应长这样:
GET /api/notes?page=1 HTTP/1.1 ← 请求行:方法 路径 版本
Host: note.example.com ← 头部区:一行一个键值对
User-Agent: curl/8.4.0
Accept: application/json
← 空行:头结束
(GET 无请求体) ← 请求体
HTTP/1.1 200 OK ← 状态行:版本 状态码 短语
Content-Type: application/json
Content-Length: 87
← 空行
{"code":0,"data":[...]}可读性的代价:解析要逐行扫描找 CRLF,头部的重复字符串没法压缩(每个请求都背一遍 User-Agent、Cookie),体积白白膨胀。
家底一:keepalive 长连接
HTTP/1.0 一问一断,每个请求都要重新三次握手 + 慢启动。1.1 默认开启 Connection: keep-alive:连接建一次,串多少个请求随意。省掉的不只是握手 RTT,还有拥塞窗口的重新爬坡——上一篇算过这笔账。服务端用 keepalive_timeout 控制空闲回收,太短形同虚设,太长白占 FD,一般 30~75 秒。
家底二:chunked 分块传输
响应体多大,最开始可能并不知道(流式生成、动态渲染)。Transfer-Encoding: chunked 允许切块发送、长度自述,不用预先生成完整内容再算 Content-Length:
HTTP/1.1 200 OK
Transfer-Encoding: chunked
4\r\n ← 本块长度(十六进制)
Wiki\r\n ← 块内容
5\r\n
pedia \r\n
0\r\n ← 长度 0 = 结束
\r\n
// 大文件下载、SSE 流式响应都靠它欠账:一连接一请求
keepalive 让请求能串行复用连接,但 1.1 规定同一连接上,前一个响应没回来,下一个请求不能发(官方的 pipelining 因为响应必须按序、中间一慢全堵,浏览器从未启用)。页面要拉 30 个资源怎么办?浏览器只好多开连接——同域名并发 6 条成为硬性上限。这条债怎么还,下一篇专讲。
用 curl 把报文看穿
$ curl -v https://note.example.com/api/notes -H "Accept: application/json"
> GET /api/notes HTTP/1.1 ← > 开头 = 发出去的
> Host: note.example.com
< HTTP/1.1 200 OK ← < 开头 = 收回来的
< Connection: keep-alive
{ ... } ← 响应体
// 排错三板斧:加 -w 看耗时分解,--resolve 绑指定 IP,-x 走代理
// HTTP 的一切行为,最终都落到这几行文本上下一篇:队头阻塞——HTTP/1.1 时代性能的天花板,以及一代人为推倒它做出的各种魔改。
评论 (0)