# 1 HTTP 报文的组成部分

⚡ 30 秒速记

  • 请求报文:请求行(方法 + 路径 + 版本)→ 请求头 → 空行 → 请求体
  • 响应报文:状态行(版本 + 状态码 + 原因短语)→ 响应头 → 空行 → 响应体
  • 空行是头和体的分界;头里混进用户输入的换行符,就能伪造头部,叫响应拆分
  • 头太大会被网关拒(431),大多是 cookie 膨胀,静态资源放无 cookie 域名
  • HTTP/2 起不再是纯文本:头部变 HEADERS 帧(HPACK 压缩),请求行变成 :method、:path 伪头,正文是 DATA 帧

HTTP/1.x 的报文就是四段:起始行、头部、空行、正文,请求和响应结构一样,只是起始行不同。 请求的起始行是方法、路径和版本,响应的是版本、状态码和原因短语。那个空行很关键,头部长度不固定,服务端读到空行才知道头结束了。实际工作里跟报文打交道最多的是头部:cookie 塞多了会触发 431,跨域加自定义头会多一次预检。到了 HTTP/2,报文变成二进制帧,概念还是这几块,但抓包时就看不到一行行的文本了。

请求报文四部分:

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 就别放头里。

③ Content-Length 和分块传输二选一。 知道总长度就用 Content-Length;流式响应(SSE、大文件、AI 逐字输出)用 Transfer-Encoding: chunked,此时没有总长度,所以做下载进度条时算不出百分比。

webapp
公众号
开发者导航
切换夜间模式
点击侧边栏上一篇
点击侧边栏下一篇
折叠侧边栏
收起全部