【问题标题】:Does HTTP content negotiation respect media type parametersHTTP 内容协商是否尊重媒体类型参数
【发布时间】:2015-08-18 11:21:55
【问题描述】:

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?即响应的media-type参数是响应正文的不准确描述?

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

【问题讨论】:

    标签: http spring-mvc content-negotiation


    【解决方案1】:

    相关标准RFC 7231 section 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 消息转换器,它们仅在其支持的媒体类型的参数上有所不同,那么 Spring 将不会可靠地选择具有与请求的媒体类型完全匹配的媒体类型的 HTTP 消息转换器。


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

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

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


    不过,section 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 错误报告,SPR-10903。 Spring 开发人员将其关闭为“按设计工作”,并指出

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

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

    【讨论】:

    【解决方案2】:

    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 错误而不响应其他媒体类型是正确的。

    【讨论】:

      猜你喜欢
      • 2014-11-15
      • 1970-01-01
      • 1970-01-01
      • 2015-08-06
      • 1970-01-01
      • 2018-07-07
      • 2015-04-01
      • 2012-05-30
      • 2016-06-12
      相关资源
      最近更新 更多