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

时间:2015-08-18 11:21:56

标签: http spring-mvc content-negotiation

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

即,如果客户请求

 Accept: application/vnd.example; version=2

(此处version参数的值为2),服务器可以投放媒体类型application/vnd.example; version=1,但不是application/vnd.example; version=2,是否可以服务器提供响应

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

服务器是否可以提供标记为

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

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

在执行内容协商时,Spring MVC 4.1.0似乎不尊重媒体类型参数,并且给出响应的媒体类型的参数对响应主体的不准确描述的响应。这似乎是因为org.springframework.util.MimeType.isCompatibleWith(MimeType)方法不检查MimeType对象的参数。

2 个答案:

答案 0 :(得分:5)

相关标准RFC 7231 section 3.1.1.1表示以下有关媒体类型的内容:

  

类型/子类型可以后跟参数形式      name = value pairs。

因此,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消息转换器,这些转换器仅在其支持的媒体类型的参数上有所不同,则Spring将无法可靠地选择具有与所请求的媒体类型完全匹配的媒体类型的HTTP消息转换器。

section 3.1.1.5中,它描述了Content-Type标题,它说:

  

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

由于媒体类型的参数通常会改变数据格式,因此Spring MVC 4.1.0的行为在提供对响应正文的不准确描述的参数时是错误的:方法{{1} }当两种类型具有同等特异性时,返回AbstractMessageConverterMethodProcessor.getMostSpecificMediaType(MediaType, MediaType)而不是acceptType是错误的。

但是,section 3.4.1讨论了内容协商(主动协商),请注意:

  

用户代理不能依赖主动协商偏好      始终如一,因为原始服务器可能无法实现      主动协商所请求的资源或可能决定      发送不符合用户代理的响应      偏好优于发送406(不可接受)响应。

因此,服务器 允许提供完全与所请求的媒体类型参数匹配的响应,作为无法准确提供的回退比赛。也就是说,它可以选择使用produceTypeToUse响应正文回复application/vnd.example; version=1标题,尽管请求说Content-Type: application/vnd.example; version=1 if,并且仅当生成时有效的Accept: application/vnd.example; version=2回复是不可能的。

这种显然不正确的Spring行为已经有了一个Spring bug报告,SPR-10903。 Spring开发人员将其关闭为" Works as Designed"注意

  

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

     
      
  • " application/vnd.example; version=2"
  •   
  • " application/vnd.spring.foo.v1+json"
  •   

答案 1 :(得分:1)

HTTP / 1.1中内容协商的相关规范是RFC2616, Section 14.1

它包含以下与您的问题相关的示例:

Accept: text/*, text/html, text/html;level=1, */*

并将优先级设为

1) text/html;level=1
2) text/html
3) text/*
4) */*

所以我认为可以说text/html;level=1text/html是不同的媒体类型。 我还会将text/html;level=1text/html;level=2视为不同。

因此,在您的示例中,我认为回复406错误并且不使用不同的媒体类型进行响应是正确的。