HTTP/1.1 是文本协议:请求行、头部、一个空行、消息体。看起来简单,但细节里藏着很多规则:怎么划分头部结束、名字大小写、必须有的 Host、什么时候关连接。这篇手工拼请求发给 example.com,逐项看服务器的真实反应,包括它比规范更宽容的地方。
发出的请求(56 字节):b'GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n'
= 请求行 "GET / HTTP/1.1"(方法 + 空格 + 目标 + 空格 + 版本)+ CRLF;头部 "Host: example.com" CRLF "Connection: close" CRLF;空行 CRLF 表示头部结束
收到 928 字节,用时 426 ms,服务器随后关闭了连接;头部 335 字节 + CRLFCRLF 4 字节 + 消息体 589 字节
0 HTTP/1.1 200 OK
1 Date: Thu, 15 Oct 2026 07:39:32 GMT
2 Content-Type: text/html; charset=utf-8
3 Transfer-Encoding: chunked
4 Connection: close
5 Server: cloudflare
6 Last-Modified: Tue, 13 Oct 2026 20:08:28 GMT
7 Allow: GET, HEAD
8 Accept-Ranges: bytes
9 Age: 6
10 cf-cache-status: HIT
11 CF-RAY: a4ad2ba5db00b5bc-HKG
12 alt-svc: h3=":443"; ma=86400
状态行:HTTP/1.1 200 OK → 版本 HTTP/1.1,状态码 200,原因短语 "OK"
头部共 12 个;Content-Length = None,实际收到的消息体 589 字节;Content-Type = ['text/html; charset=utf-8'];Transfer-Encoding = ['chunked']
消息体开头:b'241\r\n<!doctype html><html lang=en><head><meta charset=utf-8>'请求行或状态行、若干头部、空行 CRLFCRLF、消息体。响应用 chunked 划界,首行是十六进制块长度。
正常 → HTTP/1.1 200 OK 头部名字全大写 / 乱大小写 → HTTP/1.1 200 OK 冒号后无空格、值后有多余空格 → HTTP/1.1 200 OK 缺少 Host 头(HTTP/1.1 必须有) → HTTP/1.1 400 Bad Request 行尾只用 LF(没有 CR) → HTTP/1.1 200 OK 未知方法 FOO → HTTP/1.1 405 Method Not Allowed 版本号写成 HTTP/9.9 → HTTP/1.1 505 HTTP Version Not Supported 请求目标是绝对 URI → HTTP/1.1 200 OK 同一个头出现两次(Host 写两遍) → HTTP/1.1 200 OK
大小写乱、LF 行尾、绝对 URI 都被接受;缺 Host → 400,未知方法 → 405,HTTP/9.9 → 505。
请求 HTTP/1.0:响应状态行 HTTP/1.1 200 OK;响应里的 Connection = ['close'];服务器在 498 ms 时关闭了连接 请求 HTTP/1.1:响应状态行 HTTP/1.1 200 OK;响应里的 Connection = ['keep-alive'];5 秒内服务器没有关闭连接(保持着,等下一个请求)
1.0 默认关闭,1.1 默认保持;响应头的 Connection 会明确说明。
X-Pad 长度 1000:HTTP/1.1 200 OK X-Pad 长度 16000:HTTP/1.1 200 OK X-Pad 长度 64000:HTTP/1.1 200 OK X-Pad 长度 100000:HTTP/1.1 200 OK X-Pad 长度 130000:HTTP/1.1 200 OK X-Pad 长度 200000:HTTP/1.1 400 Bad Request X-Pad 长度 400000:HTTP/1.1 400 Bad Request
这个服务器单个头部值的上限在 130000~200000 字节之间,超过就是 400。