首先,HTTP 是一种类似于 MIME的协议,而不是符合MIME 的协议。引用RFC 7230,第 2.1 节:
消息以类似于 Internet 邮件 [RFC5322] 和多用途 Internet 邮件扩展 (MIME) [RFC2045] 使用的格式传递(请参阅[RFC7231] 的附录 A了解 HTTP 和 MIME 消息之间的区别)。
记住这一点很重要,因为这在处理 MIME 内容时赋予了我们一些自由。
标Accept
头受RFC 7231, sec 的约束。5.3.2 . 此处描述的语法允许使用逗号分隔的媒体类型列表(请参阅RFC 7230,第 7节),其中包含任意数量的媒体类型特定参数,每个参数以及 HTTP 特定的权重参数q
(请参阅RFC 7231,第 5.3 节)。 1 )。
第 3.1.1.1 节讨论了哪些媒体类型被认为对Accept
和Content-Type
标头有效:
HTTP在和标头字段中使用 Internet 媒体类型[RFC2046] ,以便提供开放和可扩展的数据类型和类型协商。[...] 互联网媒体类型应根据[BCP13]中定义的程序向 IANA 注册Content-Type
Accept
[BCP13] 指的是RFC 6838,最终导致IANA 媒体类型注册。
值得一提的是,Accept
标头的语法不需要任何参数。就 HTTP 规范而言,它们都是可选的。如果有必需的参数,则必须由相关媒体类型直接要求它们:
参数的存在与否对于媒体类型的处理可能很重要,这取决于它在媒体类型注册表中的定义。
multipart/related
MIME 类型本身受RFC 2387约束。第 3.1 节明确规定type
参数是强制性的。它也是一个单一的值,而不是一个列表。有趣的是,HTTP 规范在RFC 2046 第 5.1.1 节中强调了boundary
参数存在的重要性。来自RFC 7231,第 3.1.1.4 节:
正如 [RFC2046] 的第 5.1.1 节所定义的,所有多部分类型共享一个通用语法,并包括一个边界参数作为媒体类型值的一部分。
我的猜测是,作者从未想过将多部分媒体类型放入Accept
标题中,这会使边界变得无用。这确实可能是勘误表的候选者(朱利安?)。所以从技术上讲,请求这个的绝对正确的方式是:
Accept: multipart/related; type=text/html; boundary=--my-top-notch-boundary-
实际上,如本例所示,实现者似乎倾向于故意忽略这些要求。我通常不主张反对遵循 RFC,但我认为这里跳过boundary
参数实际上是有意义的。请记住,这是在内容协商中使用的请求标头,而不是对在消息部分之间具有指定边界的 seom 实际内容的描述,我想不出请求这种边界是合法的用例;除非你因为造成一些恶作剧而出局。但话说回来,你又在为自己请求一个被操纵的请求。不过,我还没有决定省略这个type
参数。恕我直言,这样做意味着type=*/*
,这实际上是“我不在乎,发送你认为合适的任何东西”。虽然这可能会导致完全符合 RFC2387 的响应,但我个人会对对返回的内容类型进行如此小的控制感到不安。(附带说明:您可能总是想检查响应的内容类型。2xx 代码并不能保证您得到了所要求的内容)
现在,如果您使用 发送请求Accept: mutlipart/related, text/html
,您将请求未指定类型的多个部分或单个 HTML 文档。如果要协商内容,则需要请求multipart/related
不同类型的几种变体:
Accept: multipart/related; type=text/html,
multipart/related; type=text/plaintext
(注意:为提高易读性而添加了续行。请注意,续行已被弃用,不应再在 HTTP 上下文中使用。)
关于你的例子,我很惊讶地发现这个媒体类型的语法在参数方面非常严格。情况如下:
- 这样的
Accept
标头受 RFC 7231, sec 的约束。5.3.2
- 根据 RFC 6838,媒体类型和子类型直接来自 IANA 媒体类型注册表
- 参数处理如下:
q
受 RFC 7231, sec 的授权。5.3.1
boundary
受 RFC 2046, sec 的授权。5.1.1
- 其余参数受媒体类型各自的 RFC 约束。在这种情况下,这意味着它
type
是必需的,后面是可选参数start
和start-info
- 根据RFC 2046 第 1 节,将丢弃无法识别的参数:
MIME 实现还必须忽略其名称无法识别的任何参数。
所以,如果level
是一个公认的参数(目前这甚至不是text/html
mediatype的情况。是的,我知道它出现在多个示例中),正确的解决方案确实是这样的:
Accept: multipart/related; type=text/html; q=0.7,
multipart/related; type=text/html; level=1,
multipart/related; type=text/html; level=2; q=0.4
但是去掉level
参数,我们可以做到这一点:
Accept: multipart/related; type=text/html; q=0.7,
multipart/related; type=text/html,
multipart/related; type=text/html; q=0.4
这在语义上与以下内容相同:
Accept: multipart/related; type=text/html