一个 HTTP 请求可以包含一个 Accept
header ,指示客户端可接受的响应媒体类型。服务器应通过提供具有与请求的媒体类型(之一)相匹配的 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;版本=1
?也就是说,响应的媒体类型参数是对响应主体的不准确描述?
似乎Spring MVC 4.1.0在进行内容协商时不尊重媒体类型参数,并给出响应的媒体类型参数是响应主体的不准确描述的响应。这似乎是因为 org.springframework.util.MimeType.isCompatibleWith(MimeType)
方法没有检查 MimeType
对象的参数。
最佳答案
相关标准,RFC 7231 section 3.1.1.1 ,关于媒体类型的说明如下:
The type/subtype MAY be followed by parameters in the form of name=value pairs.
因此,Accept
和Content-Type
header 可能包含媒体类型参数。它补充说:
The presence or absence of a parameter might be significant to the processing of a media-type, depending on its definition within the media type registry.
这表明使用参数类型的服务器代码应该注意它们,而不是简单地丢弃它们,因为对于某些媒体类型,它们将很重要。它必须在是否考虑媒体类型参数是否重要方面实现一些智能。
因此,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
header ,它说:
The indicated media type defines both the data format and how that data is intended to be processed by a recipient
由于媒体类型的参数通常会改变数据格式,因此 Spring MVC 4.1.0 的行为是错误的,因为它提供的参数是对响应主体的不准确描述:方法 AbstractMessageConverterMethodProcessor .getMostSpecificMediaType(MediaType, MediaType)
错误地返回 acceptType
而不是 produceTypeToUse
当两种类型同样具体时。
然而,section 3.4.1 ,其中讨论了内容协商(主动协商),注释:
A user agent cannot rely on proactive negotiation preferences being consistently honored, since the origin server might not implement proactive negotiation for the requested resource or might decide that sending a response that doesn't conform to the user agent's preferences is better than sending a 406 (Not Acceptable) response.
因此,服务器是允许给出一个与请求的媒体类型参数不完全匹配的响应,作为它不能提供精确匹配时的后备匹配。也就是说,它可能会选择用 application/vnd.example 进行响应; version=1
响应主体,带有 Content-Type: application/vnd.example; version=1
header ,尽管请求说 Accept: application/vnd.example; version=2
,当且仅当生成有效的application/vnd.example; version=2
响应是不可能的。
Spring 的这种明显不正确的行为已经有一个 Spring 错误报告,SPR-10903 . Spring 开发人员将其关闭为“按设计工作”,并指出
I don't know any rule for comparing media types with their parameters effectively. It really depends on the media type...If you're actually trying to achieve REST versioning through media types, it seems that the most common solution is to use different media types, since their format obviously changed between versions:
- "
application/vnd.spring.foo.v1+json
"- "
application/vnd.spring.foo.v2+json
"
关于http - HTTP 内容协商是否尊重媒体类型参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32071006/