书里把首部分成通用、请求、响应、实体四类,分的是「谁该关心它」,不是「谁发的」。 四类合计正好 47 个。
上一节讲格式,这一节讲分类。分类的意义是:看到一个新字段,能立刻知道它该出现在哪、谁负责处理。
一、四类各自的职责
| 类型 | 个数 | 典型字段 | 说明 |
|---|---|---|---|
| 通用 | 9 | Cache-Control、Date、Via |
请求和响应都可能出现 |
| 请求 | 19 | Host、Accept、Range |
客户端发,说明请求的条件 |
| 响应 | 9 | ETag、Location、Server |
服务端发,说明结果的状态 |
| 实体 | 10 | Content-Type、Content-Length |
描述正文本身 |
| 数字加起来 9+19+9+10=47,就是下一节那张一览表的行数。 | |||
| 这不是巧合——书里的分类和清单是同一套东西的两种组织方式。 |
二、分类看的是「谁该关心」
Demo 里把一个请求和一个响应里出现的每个字段都归了类。
结果有意思:Connection 出现在两边,都归通用;
Content-Type 和 Content-Length 也出现在两边,都归实体。
还有个字段被归成了「其他」:Set-Cookie。
它确实不在那 47 个里——Cookie 相关的字段由 RFC 6265 定义,不在 HTTP/1.1 的首部清单里。
这是本章很常见的一个「书里书外」交界处。
所以判断一个字段属于哪类,问的不是「它出现在请求还是响应里」,而是「它描述的对象是什么」:
描述连接和缓存的归通用,描述请求条件的归请求,描述结果的归响应,描述正文的归实体。
三、这套分类在今天已经有点旧了
2014 年之后的 HTTP 规范(RFC 7230~7235)把这套词改了一轮:
「实体首部」改叫「表示元数据」(representation metadata),
因为「实体」这个词在处理压缩和分块时会产生歧义。
更实际的变化是:Content-Length 现在同时被算作「报文定界」信息,它决定报文在哪结束,
不只是描述正文。所以严格说它一脚踩在两个类别上。
读这本书时记住四类的名字和作用就行,别把分类当教条。真要看规范,用 RFC 7230 之后的新术语。
四、动手 Demo:把一次往返里的每个字段都归一次类
发一个带五个首部的请求,服务端回一个带九个首部的响应,然后拿书里那四张清单逐个比对, 把每个字段归到它该在的类里。
GENERAL = [u'cache-control', u'connection', u'date', u'pragma',
u'trailer', u'transfer-encoding', u'upgrade', u'via',
u'warning']
REQUEST = [u'accept', u'accept-charset', ..., u'user-agent']
RESPONSE = [u'accept-ranges', u'age', u'etag', u'location', ...]
ENTITY = [u'allow', u'content-encoding', ..., u'last-modified']
def kind(k):
k = k.lower()
for names, label in ((GENERAL, u'通用'), (REQUEST, u'请求'),
(RESPONSE, u'响应'), (ENTITY, u'实体')):
if k in names:
return label
return u'其他'
实跑输出:
--------------------------------------------------------------------
通用、请求、响应、实体:四类怎么分
--------------------------------------------------------------------
【请求】
Host 请求
User-Agent 请求
Accept 请求
Accept-Encoding 请求
Referer 请求
Connection 通用
小计 请求 5 个 | 通用 1 个
【响应】
Date 通用
Server 响应
Cache-Control 通用
ETag 响应
Vary 响应
Content-Type 实体
Content-Length 实体
Last-Modified 实体
Set-Cookie 其他
Connection 通用
小计 其他 1 个 | 响应 3 个 | 实体 3 个 | 通用 3 个
四类各有多少个 通用 9、请求 19、响应 9、实体 10
合计 47 个(就是书里那张一览表的行数)
分类看的是「谁该关心它」,不是「谁发的」。
通用首部两边都可能出现;请求首部由客户端发;响应首部由服务端发;
实体首部描述的是正文本身——长度、类型、编码、校验和。
一条报文里同时出现四类是常态,别指望一条首部只有一种身份。
请求里五个字段:Host、User-Agent、Accept、Accept-Encoding、Referer 全是请求首部;
Connection 是通用。所以请求那一栏的小计是「请求 5 个 | 通用 1 个」。
响应里九个字段分得更散:Date、Cache-Control、Connection 通用,Server、ETag、
Vary 响应,Content-Type、Content-Length、Last-Modified 实体。
那个 Set-Cookie 落在「其他」——它不属于这四类里的任何一类,因为它是 RFC 6265 的字段。
四类各有 9、19、9、10 个,合计 47。
30 秒实验
- 给
Set-Cookie也加一个「Cookie/认证」类,重跑,看它在哪边出现。 - 想一想:为什么
Date被归成通用,而不是响应?(提示:请求里也能带 Date,少见但合法。) - 查一下 RFC 7230 里「表示元数据」这个词,看它替代了哪个旧词。
常见误区
- 「通用首部就是两边都能用的首部」——不止,它是「描述连接和报文本身」的首部。
- 「实体首部一定在响应里」——请求带正文时也有,比如 POST 的 Content-Type。
- 「四类覆盖了所有首部」——只覆盖 HTTP/1.1 定义的那 47 个。
自测三问(点开对答案)
1. 四类首部各有多少个,合计多少? —— 通用 9、请求 19、响应 9、实体 10,合计 47。 2. `Connection` 为什么算通用? —— 它描述的是连接本身,请求和响应里都可能出现。 3. `Set-Cookie` 属于这四类里的哪一类? —— 都不属于。它由 RFC 6265 定义,不在 HTTP/1.1 的 47 个字段里。分类清楚了。下一节把 47 个字段一次性列全。
- ☐ (本节完,下一节 6.2.4 HTTP/1.1首部字段一览)