摘要

  • RFC 2070 区分了具体 HTML 资源的外部字节编码与 HTML 固定的抽象 UCS 文档字符集;HTTP 或 MIME 的 charset 标出前者的解码映射。
  • 数字字符引用在固定的文档字符集中求值,所以无论标记由何种外部编码承载,同一个编号都保持同一字符身份。
  • 解码成功只是一张阶段性回执;SGML 解析、语言与双向文字处理、字体覆盖、字形输出和读者理解仍是不同责任人的后续状态。

设想页面要表达西里尔大写字母 И。一份资源可以在受支持的编码中直接携带它,另一份可以写成 И,第三份还能用多字节 UCS 编码存储这串引用。三份文件的八位组截然不同;如果接收方选择了正确解码器且标记有效,它们仍会落到 HTML 文档里的同一个字符编号。

RFC 2070 在这里固定的,是抽象文档中的目标,不是外部资源的字节形态。若把二者混为一谈,服务器仅仅改变传输编码就可能改变数字引用的意义。该 RFC 反过来让编号稳定,把变化限定在进入文档之前的解码边界。

SGML 先要一个字符世界,才能识别标记

当时的 HTML 是 SGML 应用。SGML 的文档字符集不是“某种文件允许出现哪些字节”,而是字符库以及文档类型和实例用来指认这些字符的编号体系。DTD、标记字符和数据字符都必须在同一个编号空间中解释。

RFC 1866 的 HTML 2.0 基线纳入 Latin-1,并令其位置与 ISO 10646 对齐,同时为更大的字符库留下方向。RFC 2070 为 HTML 2.x 国际化配置完成这一步,采用经修订的 ISO 10646:1993 通用字符集;RFC 在发布时称其逐码位等同于 Unicode 1.1。

扩大字符库并不等于允许每个整数。SGML 声明把 128 至 159 留作未使用,因此 ’ 在这个模型中仍不合法,即使后来的软件常为它显示一个排版符号。“Unicode 页面”由此至少含有两层陈述:HTML 能给哪些抽象字符编号,以及某个具体资源用什么编码把它们序列化。RFC 2070 固定了前者,并未要求后者只有一种字节编码。

charset 选择入口,不重画目的地

外部编码由传输或存储环境给出。HTTP 响应 Content-Type 的 charset 参数指认外部字符编码;电子邮件中的 MIME 参数承担同类任务,并有自己的缺省规则。RFC 2070 还明确指出,当时 FTP 或分布式文件系统没有相应的标准化信号。

MIME 的术语容易让人误会:这里的 charset 不只是字符清单,而是把八位组序列映射为字符序列的方法;甚至不同的八位组序列也可能得到同一字符结果。RFC 2045 要求一个已命名的 MIME charset 完整定义这种映射,却不保证每个抽象字符都能反向编码。

RFC 2070 用一条参考链说明职责:资源 → 解码器 → 实体管理器 → SGML 解析器 → 应用 → 显示。解码器把外部表示转换进文档字符集,后续组件再按文档字符处理语义,显示端还可转成设备表示。实现不必真的由这些同名模块组成,但从外部观察,其行为必须保留这条边界。它是一项可观察契约,不是对 1997 年浏览器内部结构的普查。

数字引用稳定,是因为它发生在解码之后

RFC 2070 把数字字符引用的不变性称为该模型最重要的结果。引用针对固定文档字符集求值,因此外部编码改变时仍指向同一字符。

顺序不能颠倒。接收方先要把字节正确还原成 &、#、数字和分号,SGML 机制随后才能识别引用并解析编号。数字引用无法修复已经被错误解码的流;它只在正确跨过解码边界后稳定。

反向也不成立:稳定的字符编号并不承诺稳定的字节。RFC 2070 提醒表单作者,未经编辑的默认值在提交时也可能变成与源文档不同但同样有效的八位组。组合序列与预组字符也可能以不同表示承载等价文本。复制、提交或保存都是新的编码事件,不能冒充原文件的逐字节复现。

编码标签也有证据优先级

RFC 2070 记录了 1997 年的部署局限:服务器常缺少恰当 charset,一些浏览器又不能正确处理带 charset 的 Content-Type。这是历史观察,不是今天的浏览器份额调查。

规范首先采用文档来源提供的 charset,其次是靠前的 META HTTP-EQUIV 声明,再其次才是链接上建议性的 CHARSET 属性。这个排序暴露出自举难题:只有前面的字节已经被解到足以找到 META,META 才能被读出。因此 RFC 称这种方法并非万无一失,其实用范围受编码开头能否适当呈现 ASCII 值字节所限。

优先级区分了权威与可得性。附近的提示也许更早出现在界面里,却不因此拥有响应元数据的权威;而权威标签也只是声明,不能从密码学上证明正文服从该映射,更不能证明解码器忠实实现了它。

字符已经解出,屏幕仍可能失败

采用 UCS 扩大了 HTML 可以指认的字符,却不会凭空制造字体。RFC 2070 预见到系统能解析但无法显示某些字符,并拒绝规定唯一回退行为。缺字方框或十六进制提示属于呈现策略,不是新的字符身份。

语言和方向还会加入更多状态。LANG 可影响字形消歧、引号、断词、连字、间距和语音;DIR、BDO 与 Unicode 双向算法会改变语义可读所需的视觉顺序。这些机制接收的是已有字符身份,不会重新定义外部字节的含义。

因此至少存在四类不同故障:编码信号错误,解码器产出错误字符,解析器拒绝或错误建树,渲染器缺字体或误用语言与方向规则。一张截图无法指出哪一层先失败,一个完好的字节哈希也不能证明后续任何一层成功。

发布机构更替后,边界仍然存在

RFC 2854 在 HTML 规范转由 W3C 维护后废止了 RFC 2070 与早期 IETF HTML 文档。这是治理与文档谱系事实,并不证明解码边界失效。后来的 text/html 注册仍把 charset 描述为 HTML 文档被表示为字节时采用的编码;HTML 4.01 也明确指出,仅有文档字符集不足以解释交换来的字节序列。

Lu Heng 后来关于“最低共同规范、地方性未来决定与运行代码”的区分,可作为有用的回看框架。固定的字符编号空间是一项小而共同的约束;接收方仍在解码器支持、错误处理、字体与呈现上作本地实现决定。规范发布不会替这些决定执行代码。

RFC 2070 的持久教训因而是:字节抵达不等于文档已经成立,字符编号解析成功也不等于字形已经出现。每次转换都要有本层证据,任何一层都不能借用上一层的回执来扩张自己的证明范围。

来源