【问题标题】:Is '*' a valid wildcard for a content type according to HTTP spec?根据 HTTP 规范,“*”是内容类型的有效通配符吗?
【发布时间】:2018-11-21 09:24:22
【问题描述】:

我们正在使用 Jax-RS 的 Jersey 参考实现。如果未指定接受标头,Jersey 的 Jax-RS 客户端实现将默认接受标头附加到请求中。默认的接受标头如下所示:

Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 

如您所见,它使用单个星号“*”作为内容类型(在 image/jpeg 之后)。

在 Jax-RS 规范中(参见 here),这个单个 * 被定义为

/**
 * The value of a type or subtype wildcard {@value #MEDIA_TYPE_WILDCARD}.
 */
public static final String MEDIA_TYPE_WILDCARD = "*";

我将其解释为“任何媒体类型的通配符”

'*/*' 定义为

/**
 * A {@code String} constant representing wildcard {@value #WILDCARD} media type .
 */
public final static String WILDCARD = "*/*";

我将其解释为“任何媒体范围的通配符”

但是,HTTP 规范 (RFC7231) 没有提到“任何媒体类型”通配符,只有媒体范围通配符:

media-range    = ( "*/*"
                 / ( type "/" "*" )
                 / ( type "/" subtype )
                 ) *( OWS ";" OWS parameter )

(..)

The asterisk "*" character is used to group media types into ranges,
with "*/*" indicating all media types and "type/*" indicating all
subtypes of that type.  The media-range can include media type
parameters that are applicable to that range.

我将其解释为允许的内容类型:

  • */*
  • 文本/*
  • 文本/纯文本

换句话说,内容类型必须始终为“某事斜线某事”或“单个 * 不是有效的内容类型”形式。虽然,后者没有明确说明。

现在这两个规范都是公开标准化的,HTTP 规范在某种程度上是 Jax-RS 规范的父文档,因为 Jax-RS 基于 HTTP。恕我直言,这两个标准在通配符内容类型方面相互矛盾。

问题是,什么是适用的?

  • 单个星号“*”是否是有效的内容类型(允许服务器以任何内容类型进行响应)
  • 还是应该使用单个星号产生错误?如果是,是哪一个?
    • 400 错误请求
    • 406 不可接受
  • 或者服务器是否应该更加宽容,并将 * 视为通配符 */* 尽管 * 不是有效的内容类型(并且可能在日志中产生警告或其他内容)?

编辑

在处理 Jsoup(不是 JaxRS/Jersey)时,我观察到 JSoup 使用相同的默认接受类型,而且似乎默认标头是 sun.net.www.protocol.http.HttpURLConnection 的实现细节

static final String acceptString = "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2";

所以如果这是一个错误,那不是 Jersey 的错误,而是 Java 的 HttpURLConnection

【问题讨论】:

  • 我认为当您说“Jersey 的 Jax-RS 客户端实现将默认接受标头附加到请求”时,了解您指的是哪个客户端很重要。你能澄清一下吗?
  • 我使用 Jersey 参考实现创建并使用了一个 Jax-RS 客户端。当我没有指定接受标头时,Jersey 会设置默认标头(请参阅此处stackoverflow.com/questions/40900870/…

标签: java http jax-rs http-accept-header


【解决方案1】:

你说:

我将其解释为“任何媒体类型的通配符”

我认为这是不正确的。它是类型或子类型的通配符。任何媒体类型的通配符都定义为*/*,就像在 HTTP 规范中一样。

此外,如有疑问,请遵循 HTTP 规范。最后,这就是您正在使用的通信协议。对方可能不知道 Jax-RS 规范。

【讨论】:

  • 所以你说,jax-rs 规范不正确(因为它使用 * 作为内容类型的通配符)?
  • @GeraldMücke 是的,它看起来像那样。另一方面,在Postel 之后,您可能希望接受来自客户端的* 并将其解释为*/*
  • JAX-RS 中的意图不同。它是目标端的匹配。这只是为了匹配传入的请求 - 它具有具体的媒体类型,例如application/json - 到服务端点。如果 ServiceEndpoint 有例如 @Produces("/json") 那么它将被使用。带有 @Produces("*/xml") 的端点显然不会。带有 @Produces(") 的 ServiceEndpoing 将匹配每个请求的 Accept。
  • 问题是,jersey客户端发送请求中的*通配符内容类型给服务端,如果服务端不是基于Jax-RS的rest服务怎么办?
  • @GeraldMücke 好吧,那肯定取决于服务器。我怀疑它会产生严重的问题,但你必须彻底测试。
【解决方案2】:

这似乎是泽西客户端库/代码的问题。

处查看 JAX-RS 规范

https://download.oracle.com/otn-pub/jcp/jaxrs-2_0-fr-eval-spec/jsr339-jaxrs-2.0-final-spec.pdf?AuthParam=1542959568_b3be8ccd614accaf7749ade85e6ebf67

,我找不到任何明确提及支持媒体类型 * 的内容。它明确提到了支持的媒体类型,例如“n/m”,其中 m 可以是 * 或 n,m 可以是 *,但只有 * 没有提及。

引用文档:

首先,让我们定义客户端媒体类型和服务器媒体类型 正如请求中的 Accept 标头和 @Produces 所表示的那样 资源方法上的注释,分别。让一个客户端媒体类型 格式为 n/m;q=v1,服务器媒体类型格式为 n/m;qs=v2 n/m;q=v1;qs=v2;d=v3 形式的组合媒体类型,其中 距离因子 d 定义如下。对于这些类型中的任何一种,m 可以是 ∗,或者 m 和 n 可以是 ∗ 并且 q 和 qs 的值被假定为 1.0 如果不存在

因此,我认为 Jersey 客户端 API 存在问题,它在没有提供明确的 Accept 标头时创建默认的 Accept 标头,并将其值设置为您提到的那个,即

Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 

另外,只是在这里添加,JAX-RS 规范提到了这一点:

(a) Filter M by removing members that do not meet the following criteria:
• The request method is supported. If no methods support the request method an implementation
MUST generate a NotAllowedException (405 status) and no entity. Note the
additional support for HEAD and OPTIONS described in Section 3.3.5.
• The media type of the request entity body (if any) is a supported input data format (see Section
3.5). If no methods support the media type of the request entity body an implementation
MUST generate a NotSupportedException (415 status) and no entity.
• At least one of the acceptable response entity body media types is a supported output data
format (see Section 3.5). If no methods support one of the acceptable response entity body
media types an implementation MUST generate a NotAcceptableException (406 status)
and no entity

因此,如果请求的媒体类型(在 Accept 标头中)无法与任何服务器支持的方法的响应媒体类型匹配,则 406 HTTP 代码将是合适的。

但是,在您的情况下,请求中指定了各种媒体类型,包括支持所有媒体类型的通用类型,因此即使 * 不完全正确,抛出错误也不是正确的做法媒体类型。

【讨论】:

  • 抛出错误恕我直言,因为请求标头字段格式错误......
  • @JulianReschke 这将使其具有限制性,并可能成为记者的障碍,因为他还指出了另一个链接,其中提到开发人员很难删除默认的 Accept 标头。此外,正如上面 Bart 所指出的,稳健性是一个值得考虑的好主意:en.wikipedia.org/wiki/Robustness_principle
  • 明白。我只是想指出根据规范可以。还要记住,剧烈的错误处理有助于保持协议干净而不会出现令人讨厌的互操作问题。请参阅 XML 或 HTTP/2。
  • 再次更新了 URL 链接,因为之前它不能正常工作。
  • 将描述中的响应代码从415更正为406。
猜你喜欢
  • 2011-06-17
  • 1970-01-01
  • 2013-04-30
  • 1970-01-01
  • 2020-07-06
  • 1970-01-01
  • 2016-12-18
  • 1970-01-01
相关资源
最近更新 更多