HTTP内容协商是否遵守媒体类型参数


问题内容

HTTP请求可以包括Accept标头,指示客户端将发现可接受的响应的媒体类型。服务器应通过提供一个Content- Type与所请求的媒体类型(之一)相匹配的响应来响应该请求。媒体类型可以包括 参数 。HTTP是否要求此内容协商过程尊重 参数

也就是说,如果客户要求

 Accept: application/vnd.example; version=2

(此处version参数的值为2),服务器可以提供media-type application/vnd.example; version=1,但不能提供media-type ,服务器是否可以application/vnd.example; version=2通过以下方式提供响应:

 Content-Type: application/vnd.example; version=1

服务器可以提供标有标签的响应吗

 Content-Type: application/vnd.example; version=2

但是对于响应的主体是否实际上被编码为media-type application/vnd.example; version=1?就是说,对于响应的媒体类型参数是否是对响应主体的不正确描述?

看起来Spring MVC
4.1.0在进行内容协商时不考虑媒体类型参数,而是给出响应,而响应的媒体类型参数是对响应主体的不准确描述。这似乎是因为该org.springframework.util.MimeType.isCompatibleWith(MimeType)方法未检查MimeType对象的参数。


问题答案:

相关标准RFC
7231第3.1.1.1节
对媒体类型说了以下几点:

类型/子类型后面可以是名称=值对形式的参数。

所以,AcceptContent-Type头可能包含媒体类型参数。它增加了:

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

这表明使用参数类型的服务器代码应注意它们,而不是 简单地 丢弃它们,因为对于某些媒体类型,它们
很重要。在考虑媒体类型参数是否重要时,它必须实现一些技巧。

因此,Spring MVC
4.1.0在进行内容协商时完全忽略参数似乎是错误的:该类org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor使用不正确org.springframework.util.MimeType.isCompatibleWith(MimeType),或者该MimeType.isCompatibleWith(MimeType)方法不正确。如果为Spring提供了几个HTTP消息转换器,这些HTTP消息转换器仅在其支持的媒体类型的参数上有所不同,Spring将不会可靠地选择其媒体类型与请求的媒体类型完全匹配的HTTP消息转换器。


3.1.1.5节中,它描述Content- Type标题的地方是:

指示的媒体类型定义了数据格式以及收件人打算如何处理该数据

由于通常媒体类型的参数可能会改变数据格式,因此Spring MVC
4.1.0的行为是错误的,因为它提供的响应主体描述不准确:AbstractMessageConverterMethodProcessor.getMostSpecificMediaType(MediaType, MediaType)返回acceptType而不是方法错误。这produceTypeToUse两种类型的含义是否相同。


但是,在讨论内容协商( 主动协商
)的3.4.1节中指出: __

用户代理不能依赖始终遵循主动协商的首选项,因为源服务器可能未对请求的资源实施主动协商,或者可能决定发送不符合用户代理首选项的响应比发送406(不接受)响应。

因此,服务器 允许给不响应 正好 符合要求的媒体类型的参数,如回退时,它不能提供精确匹配。也就是说,尽管请求说, 当且仅当
不可能生成有效响应时,它才可以选择使用application/vnd.example; version=1响应主体和Content-Type: application/vnd.example; version=1标头进行响应。Accept: application/vnd.example; version=2 __application/vnd.example; version=2


Spring的这种明显不正确的行为已经具有Spring
bug报告SPR-10903。Spring开发人员将其作为“按设计工作”关闭,并指出

我不知道有效地比较媒体类型及其参数的任何规则。这实际上取决于媒体类型…如果您实际上试图通过媒体类型实现REST版本控制,则似乎最常见的解决方案是使用不同的媒体类型,因为它们的格式在版本之间显然发生了变化:

  • application/vnd.spring.foo.v1+json
  • application/vnd.spring.foo.v2+json