2

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

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

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

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

/**
 * 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.

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

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

换句话说,内容类型必须始终采用“something slash something”或“单个 * is not a valid content type”的形式。虽然,后者没有明确说明。

现在这两个规范都是公开标准化的,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";

因此,如果这是一个错误,那不是泽西岛的错误,而是 Java 的 HttpURLConnection

4

2 回答 2

2

你说:

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

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

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

于 2018-11-21T09:33:03.720 回答
1

泽西客户端库/代码似乎有问题。

浏览 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 代码将是合适的。

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

于 2018-11-21T11:44:32.480 回答