HTTP 结构化头部字段值规范的 Swift 实现。
提供结构化头部字段值的解析和序列化功能,以及 Encoder
和 Decoder
的实现,允许使用 Codable
数据类型作为 HTTP 结构化头部字段的有效载荷。
HTTP 结构化头部字段值是 RFC 9651 中记录的 HTTP 扩展。它们提供了一组数据类型和算法,用于以一致的方式处理 HTTP 头部字段值,允许单个解析器和序列化器处理各种头部字段值。
此包提供了一个实现 RFC 9651 的解析器和序列化器。它们是完全完整的,能够处理所有有效的 HTTP 结构化头部字段值。此包还提供了 Encoder
和 Decoder
对象,用于在 Swift 中使用 Codable。这允许快速原型设计和实验 HTTP 结构化头部字段值,以及与更广泛的 Swift Codable 社区进行交互。
此包提供两个顶级模块:StructuredFieldValues
和 RawStructuredFieldValues
。
基础模块 RawStructuredFieldValues
提供了序列化器和解析器的底层实现。这两者都编写为避免使用 Foundation,使其适用于 Foundation 不可用的各种用例。它们完全依赖于 Swift 标准库,并尽可能以通用方式实现。由于缺少 Foundation,其中一个限制是此接口无法执行 Base64 编码或解码:用户可以自由选择他们使用的任何编码器和解码器。
这个 API 是底层的,将原始解析树暴露为序列化器和解析器的格式。这允许高性能和高灵活性的解析和序列化,但代价是冗长而复杂。用户需要理解结构化头部格式并操作稍微笨拙的类型,但保留了最大的保真度,并且性能开销很低。
高级模块 StructuredFieldValues
引入了 Encoder
和 Decoder
,并且还添加了对 Foundation 的依赖。这个 Foundation 依赖项对于正确处理 base64 格式以及为二进制数据(Data
)和日期(Date
)提供良好的自然容器是必要的。此接口更加友好且易于使用,使用 Swift 的 Codable
支持来提供出色的用户体验。
在大多数情况下,用户应首选使用 StructuredFieldValues
,除非他们知道他们需要 RawStructuredFieldValues
的性能优势。体验会好得多。
swift-http-structured-headers
具有一个简单易用的高级 API,用于处理结构化头部字段值。首先,让我们考虑 HTTP 客户端提示规范。 这定义了以下新的头部字段
Accept-CH 响应头字段指示服务器支持其值中指示的提示。希望通过客户端提示接收用户代理信息的服务器应尽快将 Accept-CH 响应头添加到其响应中。
Accept-CH 是一个结构化头部。它的值必须是一个 sf-list,其成员是 token。其 ABNF 是
Accept-CH = sf-list
例如
Accept-CH: Sec-CH-Example, Sec-CH-Example-2
swift-http-structured-headers
可以非常简单地解析和序列化此字段
let field = Array("Sec-CH-Example, Sec-CH-Example-2".utf8)
struct AcceptCH: StructuredFieldValue {
static let structuredFieldType: StructuredFieldType = .list
var items: [String]
}
// Decoding
let decoder = StructuredFieldValueDecoder()
let parsed = try decoder.decode(AcceptCH.self, from: field)
// Encoding
let encoder = StructuredFieldValueEncoder()
let serialized = try encoder.encode(AcceptCH(items: ["Sec-CH-Example", "Sec-CH-Example-2"]))
但是,结构化头部字段值可能相当复杂。 结构化头部字段可以使用 4 个容器和 8 种基本项目类型。 容器是
StructuredFieldValues
可以将字典建模为 Swift 对象(其中属性名称是字典键)。StructuredFieldValues
将这些建模为具有一个键 items
的 Swift 对象,该键必须是条目的集合。StructuredFieldValues
将这些建模为 Swift Array
或,如果提取参数很重要,则建模为双字段 Swift struct
,其中一个字段名为 items
并包含一个 Array
,另一个字段名为 parameters
并包含一个字典。StructuredFieldValues
将这些建模为 Swift 对象(其中属性名称是参数键)或 Swift 字典。基本类型是
StructuredFieldValues
将这些建模为 Swift 的 Bool
类型。StructuredFieldValues
将这些建模为任何固定宽度的整数类型。StructuredFieldValues
将这些建模为任何浮点类型,或 Foundation 的 Decimal
。StructuredFieldValues
将这些建模为 Swift 的 String
类型,其中字符范围受到限制。StructuredFieldValues
将这些建模为 Swift 的 String
类型。StructuredFieldValues
将此建模为 Foundation 的 Data
类型。StructuredFieldValues
将这些建模为 Foundation 的 Date
类型。StructuredFieldValues
将这些建模为它提供的 DisplayString
类型。对于任何结构化头部字段值项,该项目可以直接由适当的类型表示,也可以由具有两个属性的 Swift 结构表示:item
和 parameters
。 后一种模式是如何捕获给定项目上的参数。
顶级结构化头部字段值必须标识它对应的头部字段的类型:.item
、.list
或 .dictionary
。 这是字段类型固有的,将在相关的字段规范中指定。
在某些情况下,Codable 接口对于预期的用例来说不够高效或强大。 在这种情况下,用户可以使用 RawStructuredFieldValues
模块中的类型。
有两个核心类型:StructuredFieldValueParser
和 StructuredFieldValueSerializer
。 这两个对象不使用高级 Swift 对象,而是生成或接受给定结构化头部字段的数据树的 Swift 表示。
这暴露了有关头部字段的最大量信息。 它允许用户处理 Codable 不一定能提供相关信息的情况,例如在字典排序具有语义的情况下,或者需要更紧密地控制字段是 token 还是字符串的情况下。
这些 API 的开销也比 StructuredFieldValues
API 低。
代价是这些 API 更加冗长。 考虑上面的头部字段 Accept-CH
。 在 RawStructuredFieldValues
中解析或序列化它会是这样
let field = Array("Sec-CH-Example, Sec-CH-Example-2".utf8)
var parser = StructuredFieldValueParser(field)
let parsed = parser.parseListFieldValue()
print(parsed)
// [
// .item(Item(bareItem: .token("Sec-CH-Example"), parameters: [])),
// .item(Item(bareItem: .token("Sec-CH-Example-2"), parameters: [])),
// ]
var serializer = StructuredFieldValueSerializer()
let serialized = serializer.writeListFieldValue(parsed)
请注意此操作中涉及的类型明显更加冗长。 这些类型具有高度通用性,从而为解析和序列化提供了大大减少运行时开销的机会。 它们还可以更容易地区分 token 和字符串,并观察字典或参数中对象的顺序,这可能会在 Codable 级别丢失。
一般来说,用户只有在确信他们需要灵活性或性能时才应考虑使用此 API。 对于不经常演变或高度动态的头部字段,这可能很有价值。
swift-http-structured-headers 在 SECURITY.md 中概述了安全策略。