📘 第六章 HTTP首部
📄 一句话概括

书里把首部分成通用、请求、响应、实体四类,分的是「谁该关心它」,不是「谁发的」。 四类合计正好 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 秒实验

  1. 给 Set-Cookie 也加一个「Cookie/认证」类,重跑,看它在哪边出现。
  2. 想一想:为什么 Date 被归成通用,而不是响应?(提示:请求里也能带 Date,少见但合法。)
  3. 查一下 RFC 7230 里「表示元数据」这个词,看它替代了哪个旧词。

常见误区

  1. 「通用首部就是两边都能用的首部」——不止,它是「描述连接和报文本身」的首部。
  2. 「实体首部一定在响应里」——请求带正文时也有,比如 POST 的 Content-Type。
  3. 「四类覆盖了所有首部」——只覆盖 HTTP/1.1 定义的那 47 个。
自测三问(点开对答案) 1. 四类首部各有多少个,合计多少? —— 通用 9、请求 19、响应 9、实体 10,合计 47。 2. `Connection` 为什么算通用? —— 它描述的是连接本身,请求和响应里都可能出现。 3. `Set-Cookie` 属于这四类里的哪一类? —— 都不属于。它由 RFC 6265 定义,不在 HTTP/1.1 的 47 个字段里。

分类清楚了。下一节把 47 个字段一次性列全。

相关笔记