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
对象的参数。
答案 0 :(得分:5)
相关标准RFC 7231 section 3.1.1.1表示以下有关媒体类型的内容:
类型/子类型可以后跟参数形式 name = value pairs。
因此,Accept
和Content-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=1
和text/html
是不同的媒体类型。
我还会将text/html;level=1
和text/html;level=2
视为不同。
因此,在您的示例中,我认为回复406错误并且不使用不同的媒体类型进行响应是正确的。