7

RFC 7231 - HTTP/1.1 Semantics and Content, 5.3 Content Negotiation没有定义如何在接受头字段中指定如何接受具有特定内容类型的多部分/相关内容类型。

例如,如何用 text/html 正文部分表达对多部分/相关内容的接受

Accept: multipart/related;type=text/html

或者

Accept: multipart/related,text/html

如果你想为不同的 html 风格指定优先级?

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

或者

Accept: multipart/related,text/html;q=0.7,
   text/html;level=1,
   text/html;level=2;q=0.4

什么是对的?两个都?

4

2 回答 2

8

首先,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 节讨论了哪些媒体类型被认为对AcceptContent-Type标头有效:

HTTP在和标头字段中使用 Internet 媒体类型[RFC2046] ,以便提供开放和可扩展的数据类型和类型协商。[...] 互联网媒体类型应根据[BCP13]中定义的程序向 IANA 注册Content-TypeAccept

[BCP13] 指的是RFC 6838,最终导致IANA 媒体类型注册

值得一提的是,Accept标头的语法不需要任何参数。就 HTTP 规范而言,它们都是可选的。如果有必需的参数,则必须由相关媒体类型直接要求它们:

参数的存在与否对于媒体类型的处理可能很重要,这取决于它在媒体类型注册表中的定义。

multipart/relatedMIME 类型本身受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是必需的,后面是可选参数startstart-info
    • 根据RFC 2046 第 1 节,将丢弃无法识别的参数:

MIME 实现还必须忽略其名称无法识别的任何参数。

所以,如果level是一个公认的参数(目前这甚至不是text/htmlmediatype的情况。是的,我知道它出现在多个示例中),正确的解决方案确实是这样的:

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
于 2016-03-31T13:38:16.317 回答
0

实际上,它确实定义了它——它说允许可选参数。如何解释这些取决于媒体类型定义,而不是 Accept 标头字段的语法。

于 2016-03-31T12:40:08.577 回答