Aller au contenu principal

1. Introduction (简介)

指定新HTTP头部 (header) 和尾部 (trailer) 字段的语法是一项繁重的任务;即使有[RFC7231]第8.3.1节的指导,对于潜在的HTTP字段作者来说,仍然存在许多决策和陷阱。

一旦定义了字段,通常需要编写定制的解析器和序列化器,因为每个字段值对看似通用的语法都有稍微不同的处理方式。

本文档引入了一组通用数据结构,用于新HTTP字段值的定义,以解决这些问题。特别是,它为这些数据结构定义了一个通用的抽象模型,以及在HTTP [RFC7230] 头部和尾部字段中表达该模型的具体序列化方式。

被定义为"结构化头部 (Structured Header)"或"结构化尾部 (Structured Trailer)"的HTTP字段(如果字段可以是两者之一,则称为"结构化字段 (Structured Field)")使用本规范中定义的类型来定义其语法和基本处理规则,从而简化了规范编写者的定义工作和实现者的处理工作。

此外,HTTP的未来版本可以定义这些结构抽象模型的替代序列化方式,允许使用该模型的字段更高效地传输,而无需重新定义。

请注意,本文档的目标不是重新定义现有HTTP字段的语法;此处描述的机制仅适用于明确选择使用它们的字段。

第2节描述了如何指定结构化字段。

第3节定义了可在结构化字段中使用的多种抽象数据类型。

这些抽象类型可以使用第4节中描述的算法序列化为HTTP字段值或从HTTP字段值解析。


1.1 Intentionally Strict Processing (有意的严格处理)

本规范有意地使用逐步算法定义严格的解析和序列化行为;唯一定义的错误处理是完全使操作失败。

这样设计是为了鼓励忠实的实现和良好的互操作性。因此,试图通过对输入更加宽容来"提供帮助"的实现,实际上会使互操作性变得更糟,因为这会给其他实现施加压力,让它们实现类似(但可能微妙不同)的变通方案。

换句话说,严格处理是本规范的有意特性;它允许尽早发现和纠正不合规的输入,并避免可能导致的互操作性和安全问题。

请注意,由于这种严格性,如果字段由多方追加(例如,中间代理或发送方的不同组件),其中一方的值中的错误可能会导致整个字段值解析失败。


1.2 Notational Conventions (符号约定)

本文档中的关键词"MUST"、"MUST NOT"、"REQUIRED"、"SHALL"、"SHALL NOT"、"SHOULD"、"SHOULD NOT"、"RECOMMENDED"、"NOT RECOMMENDED"、"MAY"和"OPTIONAL"应按BCP 14 [RFC2119] [RFC8174]中的描述进行解释,当且仅当它们以全大写形式出现时(如此处所示)。

本文档使用算法来指定解析和序列化行为,并使用[RFC5234]的扩充巴科斯-瑙尔范式 (ABNF) 表示法来说明HTTP头部字段中的预期语法。在此过程中,它使用[RFC5234]中的VCHAR、SP、DIGIT、ALPHA和DQUOTE规则。它还包含[RFC7230]中的tchar和OWS规则。

从HTTP字段解析时,实现必须 (MUST) 具有与遵循算法无法区分的行为。如果解析算法与ABNF之间存在分歧,则以指定的算法为准。

对于序列化到HTTP字段,ABNF说明了它们的预期线路表示,算法定义了产生它们的推荐方式。实现可以 (MAY) 偏离指定的行为,只要输出仍然能被第4.2节中描述的解析算法正确处理。


关键要点 (Key Takeaways)

1. 问题背景

传统HTTP字段定义的痛点:

# 每个字段都有自己的语法:
Cache-Control: max-age=3600, private
Accept: text/html, application/json;q=0.9
Content-Type: text/html; charset=utf-8
Link: `https://example.com`; rel="preload"

# 结果:
- 每个字段需要自定义解析器
- 看似相似的语法实际上有微妙差异
- 容易出错,难以维护

2. 解决方案

结构化字段提供:

  • 统一的数据类型: Integer, String, Boolean, List, Dictionary等
  • 标准化的序列化: 一致的格式规则
  • 明确的解析算法: 消除歧义
  • 向前兼容: 未来可以使用更高效的编码

3. 严格性哲学

❌ 错误示例 - 宽容的解析器:
输入: key="value (缺少结束引号)
宽容解析: 自动补全引号,解析成功

问题:
- 不同实现可能有不同的"修复"方式
- 导致不可预测的行为
- 创建安全漏洞

✓ 正确示例 - 严格的解析器:
输入: key="value (缺少结束引号)
严格解析: 立即失败,返回错误

好处:
- 强制生产者生成正确的格式
- 确保所有实现行为一致
- 尽早发现问题

4. 设计目标

  • 不重新定义现有字段: 仅用于新字段
  • 抽象 + 具体: 抽象模型 + HTTP/1.1序列化
  • 未来可扩展: 可为HTTP/2、HTTP/3定义新序列化

5. 文档结构

第2节: 如何定义结构化字段 → 给规范作者的指南
第3节: 抽象数据类型 → List, Dictionary, Item等
第4节: 序列化和解析算法 → 具体实现细节

实际影响

对规范作者

传统方式:
---------
定义新字段 "Example-Field"
- 编写自定义ABNF语法
- 详细说明解析规则
- 处理边界情况
- 定义错误处理
(可能需要数十页文档)

结构化字段方式:
-------------
定义新字段 "Example-Field"
- 引用RFC 8941
- 说明它是Dictionary类型
- 定义键和值的含义
(可能只需要几段文字)

对实现者

// 传统方式 - 每个字段都需要自定义解析器
function parseCacheControl(value) {
// 50-100行代码...
}
function parseAccept(value) {
// 另外50-100行代码...
}
function parseContentType(value) {
// 又是50-100行代码...
}

// 结构化字段方式 - 通用解析器
const cacheControl = parseDictionary(header); // 复用
const accept = parseList(header); // 复用
const contentType = parseItem(header); // 复用

对网络效率

HTTP/1.1: 文本格式
Example-Dict: a=1, b=2, c=3

HTTP/2 (未来): 可能的二进制编码
[0x01] [dict] [3 items] [a:1] [b:2] [c:3]
↑ 更紧凑,但逻辑相同

适用场景

✓ 应该使用结构化字段

  • 定义新的HTTP头部
  • 需要复杂数据结构 (列表、字典)
  • 希望未来支持更高效编码
  • 追求良好的互操作性

✗ 不应该使用结构化字段

  • 已经定义的现有字段 (如Cache-Control)
  • 简单的单值字段 (可以,但不是必须)
  • 需要向后兼容旧客户端的字段