# 1 HTTP 报文的组成部分
⚡ 30 秒速记
- 请求报文:请求行(方法 + 路径 + 版本)→ 请求头 → 空行 → 请求体
- 响应报文:状态行(版本 + 状态码 + 原因短语)→ 响应头 → 空行 → 响应体
- 空行是关键分隔符 —— 头部变长,服务端靠它判断"头结束了";头里混入裸换行就能伪造分隔(
HTTP响应拆分攻击) - 头部过大会被网关拒绝(431),最常见的原因是
cookie膨胀 —— 所以静态资源要放无cookie域名 Content-Length和Transfer-Encoding: chunked二选一,流式响应用后者,所以下载进度条算不出百分比- ⚠️
HTTP/2起头部被压成HEADERS帧、body 是DATA帧,不再是纯文本,但四部分的概念划分仍成立
HTTP/1.x 请求报文由请求行、请求头、空行和请求体组成,响应报文对应状态行、响应头、空行和响应体。 空行是头部与正文的关键分隔,因为头部长度不固定;字段中混入裸换行还可能造成 HTTP 响应拆分。工程上要留意头部过大可能触发 431,常见诱因是同域 cookie 膨胀,因此静态资源可使用无 cookie 域名。已知长度用 Content-Length,流式响应通常用 Transfer-Encoding: chunked;到了 HTTP/2,内容改由 HEADERS 和 DATA 帧承载,但概念划分仍成立。
请求报文四部分:
POST /api/order HTTP/1.1 ← 请求行:方法 + 路径 + 协议版本
Host: api.example.com ← 请求头
Content-Type: application/json
Content-Length: 27
← 空行(关键分隔符)
{"id":123,"count":1} ← 请求体
响应报文四部分:
HTTP/1.1 200 OK ← 状态行:协议版本 + 状态码 + 原因短语
Content-Type: application/json ← 响应头
Cache-Control: no-cache
← 空行
{"code":0,"data":{}} ← 响应体
那个空行为什么重要?
因为 HTTP 头部是变长的 —— 服务端读到一个空行才知道"头结束了,后面是 body"。这也是为什么头部字段不能包含裸的换行符,否则就能伪造出一个假的分隔,这类攻击叫 HTTP 响应拆分。
实际工作中会遇到的几个细节:
① 头部太大会被拒绝。 常见于 cookie 膨胀 —— 每个同域请求都会带上全域 cookie,塞多了轻松几 KB,超过网关限制就返回 431 或直接被断开。所以静态资源该放独立的无 cookie 域名。
② 自定义请求头有代价。 跨域时会触发 OPTIONS 预检,等于每个请求变两个往返;中间的 CDN/网关也可能不透传未知的头。能放 body 就别放头里。