书里列了 47 个字段。 但一次真实的 GET 只能碰到十七个左右——47 是「规范定义了」的数量,不是「你会用到」的数量。
上一节分了四类,这一节把四类里的字段全部摊开。接下来的 6.3 到 6.6 会一个个细讲这 47 个。
一、47 的分部
| 分类 | 字段 |
|---|---|
| 通用 1/3 | Cache-Control、Connection、Date |
| 通用 2/3 | Pragma、Trailer、Transfer-Encoding |
| 通用 3/3 | Upgrade、Via、Warning |
| 请求 1/7 | Accept、Accept-Charset、Accept-Encoding |
| 请求 2/7 | Accept-Language、Authorization、Expect |
| 请求 3/7 | From、Host、If-Match |
| 请求 4/7 | If-Modified-Since、If-None-Match、If-Range |
| 请求 5/7 | If-Unmodified-Since、Max-Forwards |
| 请求 6/7 | Proxy-Authorization、Range、Referer |
| 请求 7/7 | TE、User-Agent |
| 响应 1/3 | Accept-Ranges、Age、ETag |
| 响应 2/3 | Location、Proxy-Authenticate、Retry-After |
| 响应 3/3 | Server、Vary、WWW-Authenticate |
| 实体 1/4 | Allow、Content-Encoding、Content-Language |
| 实体 2/4 | Content-Length、Content-Location、Content-MD5 |
| 实体 3/4 | Content-Range、Content-Type、Expires |
| 实体 4/4 | Last-Modified |
| 这张表就是本章后半部分的地图:6.3 讲通用、6.4 讲请求、6.5 讲响应、6.6 讲实体,加起来正好四十七节。 |
二、实测只碰到 17 个
Demo 里发了一个带六个首部的 GET,又让服务端回了九个首部,两边合起来去重,
47 个里只出现了 17 个,占 36%。
没出现的那 30 个,基本都属于「要特定条件才出现」:
| 类别 | 例子 | 什么时候才出现 |
|---|---|---|
| 代理专用 | Via、Max-Forwards、Proxy-Authenticate | 走代理时 |
| 条件请求 | If-* 系列五个 | 有缓存副本时 |
| 上传下载 | Content-Range、Content-MD5 | 断点续传、校验时 |
| 内容协商 | Accept-Charset、Content-Language | 多语言站点 |
| 认证 | Authorization、WWW-Authenticate | 需要登录时 |
所以「记住 47 个」是没必要的。真正该记住的是「哪一类里有什么」,剩下的用时查。
三、这个数字还会变
47 是 HTTP/1.1(1999 年)的清单。
之后新增的字段都不在这个表里:Alt-Svc、Strict-Transport-Security、Content-Security-Policy、
Forwarded、Early-Data……
被废弃的也不在:Keep-Alive 从来没进过标准清单,Warning 在 2015 年被标记废弃,
Content-MD5 因为不够安全而被 Digest 系列取代。
所以这张表要当成「1999 年的快照」,而不是「今天该知道的全部」。
四、动手 Demo:47 个字段的实测覆盖率
把书里四类的 47 个字段写成四张清单,发一次真实请求,然后把请求和响应里出现过的字段名都收进来, 逐个标注「出现/没出现」。
ALL = {
u'通用': [u'Cache-Control', u'Connection', u'Date', ...],
u'请求': [u'Accept', u'Accept-Charset', ..., u'User-Agent'],
u'响应': [u'Accept-Ranges', ..., u'WWW-Authenticate'],
u'实体': [u'Allow', ..., u'Last-Modified'],
}
hit = 0
for grp, names in ALL.items():
got = [n for n in names if n.lower() in seen]
hit += len(got)
print(u'【%s首部】%d 个里出现 %d 个' % (grp, len(names), len(got)))
实跑输出:
--------------------------------------------------------------------
书里那 47 个字段,一次真跑的会话里能见到几个
--------------------------------------------------------------------
【通用首部】9 个里出现 3 个
Cache-Control 出现
Connection 出现
Date 出现
Pragma 没出现
Trailer 没出现
Transfer-Encoding 没出现
Upgrade 没出现
Via 没出现
Warning 没出现
【请求首部】19 个里出现 7 个
Accept 出现
Accept-Charset 没出现
Accept-Encoding 出现
Accept-Language 出现
Authorization 没出现
Expect 没出现
From 没出现
Host 出现
If-Match 没出现
If-Modified-Since 没出现
If-None-Match 没出现
If-Range 没出现
If-Unmodified-Since 没出现
Max-Forwards 没出现
Proxy-Authorization 没出现
Range 出现
Referer 出现
TE 没出现
User-Agent 出现
【响应首部】9 个里出现 4 个
Accept-Ranges 出现
Age 没出现
ETag 出现
Location 没出现
Proxy-Authenticate 没出现
Retry-After 没出现
Server 出现
Vary 出现
WWW-Authenticate 没出现
【实体首部】10 个里出现 3 个
Allow 没出现
Content-Encoding 没出现
Content-Language 没出现
Content-Length 出现
Content-Location 没出现
Content-MD5 没出现
Content-Range 没出现
Content-Type 出现
Expires 没出现
Last-Modified 出现
书里一共 47 个
这次跑到 17 个(36%)
没见到的 30 个
没见过的这些,基本都属于「要特定条件才出现」:
Pragma、Trailer、Transfer-Encoding、Upgrade、Via、Warning、Accept-Charset、Authorization、Expect、From、If-Match、If-Modified-Since、If-None-Match、If-Range、If-Unmodified-Since、Max-Forwards、Proxy-Authorization、TE、Age、Location
Proxy-Authenticate、Retry-After、WWW-Authenticate、Allow、Content-Encoding、Content-Language、Content-Location、Content-MD5、Content-Range、Expires
47 这个数字不是「你会用到的数量」,而是「规范定义了的数量」。
日常一次 GET 能碰到十几个;剩下那些要么是条件请求专用,
要么是代理专用,要么是上传下载专用。
所以别背清单,记清楚「哪一类里有什么」就够了。
通用 9 个里出现 3 个(Cache-Control、Connection、Date);请求 19 个里出现 7 个;
响应 9 个里出现 4 个;实体 10 个里出现 3 个。
合计 17 个,36%。
剩下 30 个没出现——它们的名字在输出里全列出来了,可以对照自己的项目看哪些其实用过。
顺手能发现一件事:Range 出现在请求那一栏里、Accept-Ranges 出现在响应里。
这对字段是一问一答——客户端说「我要一段」,服务端说「我支持分段」。
30 秒实验
- 再加一个走代理的请求(带
Via)和一个Range请求,看能多覆盖几个。 - 把服务端改成回
401加WWW-Authenticate,看那个字段长什么样。 - 想一想:为什么
Keep-Alive不在这个 47 个里,但抓包时经常看到?
常见误区
- 「47 个首部要背下来」——按类记结构就行,具体名字用时查。
- 「不在 47 个里就不是标准字段」——很多字段由别的 RFC 定义,或者成了事实标准。
- 「这 47 个是今天的全部」——这是 1999 年的快照,之后新增废弃都很多。
自测三问(点开对答案)
1. 四类各有多少个,合计多少? —— 通用 9、请求 19、响应 9、实体 10,合计 47。 2. 为什么一次普通 GET 只能碰到十几个? —— 很多字段要特定条件才出现:走代理、有缓存副本、要认证、要分段传输等。 3. `Range` 和 `Accept-Ranges` 是什么关系? —— 一问一答:客户端用 Range 请求某一段,服务端用 Accept-Ranges 声明支持分段。47 个说完了。接下来看那些不在这张表里的字段——它们同样天天在用。
- ☐ (本节完,下一节 6.2.5 非HTTP/1.1首部字段)