在所有 JSON 生产端点上使用 @Produces("application/json") 是好的做法吗?
Is it good practice to use @Produces("application/json") on all JSON producing endpoints?
我们开始将 Jersey/JAX-RS 用于我们的 front-end 代码使用的内部 REST 端点。必须 return 结果的端点总是发送 JSON objects.
出于调试目的,我们使用 firefox restclient 扩展。直到最近,我只会输入 URL 并点击发送,然后会返回显示为 JSON.
的内容
但是当我今天早上这样做时,FF 扩展返回并告诉我必须将响应类型更改为二进制 (BLOB)。这样做会导致显示编码字符串而不是 JSON.
我可以通过设置请求 header(Accept:
为 application/json
)来解决这个问题。
在进行更多研究后,我发现了这个 question。我的 结论 是:我们可能应该将 @Produces("application/json")
添加到所有这些端点。
问题:真的那么简单,还是有充分的技术理由不这样做?
Is it good practice to use @Produces("application/json")
on all JSON producing endpoints?
如果您的资源方法产生 JSON 作为资源的表示,它们 应该 用 @Produces(MediaType.APPLICATION_JSON)
注释。因此,响应将有一个 Content-Type
header 指示有效负载的媒体类型。
@Produces
annotation is also used for request matching: The JAX-RS runtime matches the media type sent in the Accept
header with the media type defined in the @Produces
注释。
如果您不想注释应用程序中的每个资源方法,您可以改为注释资源 classes。它将指示在此类 class 中定义的所有方法必须生成 JSON 作为您的资源的表示。
在应用程序中注册的 @Produces
annotation indicates the media type that will be produced by the MessageBodyWriter
个实例中定义的媒体类型。考虑以下示例:
@GET
@Produces(MediaType.APPLICATION_JSON)
public Foo getFoo() {
Foo foo = new Foo();
return Response.ok(foo).build();
}
一旦 getFoo()
方法被 @Produces(MediaType.APPLICATION_JSON)
注释,JAX-RS 将把 Foo
实例写入 JSON 文档。它在 MessageBodyWriter
implementation. If your application uses Jackson, for example, the JacksonJsonProvider
中完成,将用于将 Java objects 转换为 JSON 文件。
为了Content Negotiation 和 HTTP 协议的正确性。如果没有这些注释,结果将取决于客户端请求和服务器的默认行为(在不同的实现中可能不同),这会导致不可预测和不明确的结果。
通过这些注释,我们宣传我们可以生产和消费哪些媒体类型。在检索 (GET) 请求中,客户端应发送 Accept
header 以及他们期望返回的资源的媒体类型。在创建请求(PUT,POST)时,客户端应该发送 Content-Type
header 告诉服务器他们发送的数据是什么媒体类型。如果这些 header 与服务器宣传要处理的内容不匹配,那么客户端将收到错误响应,告诉他们问题出在哪里;使用检索请求和 non-matching Accept
header,响应将是 406 Not Acceptable. With a Create request and a non-matching Content-Type
header, the response will be a 415 Unsupported Media Type.
这就是内容协商的工作原理。为了确保我们的服务器按照客户的期望运行,我们应该声明我们可以在服务器上处理什么。注释就是这样做的。
如您所述,当您离开 @Produces
时,客户告诉您需要更改响应类型。这是因为结果是 Content-Type
响应 header 被设置为 application/octet-stream
,这就是 the answers here 的结论。客户端使用 Content-Type
header 来确定如何处理响应。
最后一个示例是针对检索请求的。如果我们在 Create 端点上离开 @Consumes
,很多不同的事情都会出错。举个例子,我们有一个我们想要接受 JSON 的端点,所以我们创建一个 POJO 来将 JSON 映射到。
@POST
public Response create(Customer customer) {}
要使其正常工作,取决于客户端将请求中的 Content-Type
header 设置为 application/json
。但是如果没有 @Consumes
注释,我们基本上是在宣传这个端点能够接受 any 媒体类型,这太荒谬了。 @Consumes
注释就像守卫说 "If you don't send the right type of data, you cannot pass"。但是由于我们没有守卫,所有的数据都被允许通过,结果是不可预测的,因为根据客户端设置 Content-Type
的内容,我们不知道 MessageBodyReader
1 将处理从实体 body 到 Customer
的转换。如果没有选择正确的 MessageBodyReader
(将 JSON 转换为 POPJO 的那个),那么很可能会导致异常,并且客户端将返回 500 Internal Server Error,这不是与获得 415 不支持的媒体类型一样具体。
1. See chapter 8 and 9 of the Jersey docs。它将解释如何分别使用 MessageBodyReader
和 MessageBodyWriter
将实体主体转换为 Java objects(反之亦然)。
我们开始将 Jersey/JAX-RS 用于我们的 front-end 代码使用的内部 REST 端点。必须 return 结果的端点总是发送 JSON objects.
出于调试目的,我们使用 firefox restclient 扩展。直到最近,我只会输入 URL 并点击发送,然后会返回显示为 JSON.
的内容但是当我今天早上这样做时,FF 扩展返回并告诉我必须将响应类型更改为二进制 (BLOB)。这样做会导致显示编码字符串而不是 JSON.
我可以通过设置请求 header(Accept:
为 application/json
)来解决这个问题。
在进行更多研究后,我发现了这个 question。我的 结论 是:我们可能应该将 @Produces("application/json")
添加到所有这些端点。
问题:真的那么简单,还是有充分的技术理由不这样做?
Is it good practice to use
@Produces("application/json")
on all JSON producing endpoints?
如果您的资源方法产生 JSON 作为资源的表示,它们 应该 用 @Produces(MediaType.APPLICATION_JSON)
注释。因此,响应将有一个 Content-Type
header 指示有效负载的媒体类型。
@Produces
annotation is also used for request matching: The JAX-RS runtime matches the media type sent in the Accept
header with the media type defined in the @Produces
注释。
如果您不想注释应用程序中的每个资源方法,您可以改为注释资源 classes。它将指示在此类 class 中定义的所有方法必须生成 JSON 作为您的资源的表示。
在应用程序中注册的 @Produces
annotation indicates the media type that will be produced by the MessageBodyWriter
个实例中定义的媒体类型。考虑以下示例:
@GET
@Produces(MediaType.APPLICATION_JSON)
public Foo getFoo() {
Foo foo = new Foo();
return Response.ok(foo).build();
}
一旦 getFoo()
方法被 @Produces(MediaType.APPLICATION_JSON)
注释,JAX-RS 将把 Foo
实例写入 JSON 文档。它在 MessageBodyWriter
implementation. If your application uses Jackson, for example, the JacksonJsonProvider
中完成,将用于将 Java objects 转换为 JSON 文件。
为了Content Negotiation 和 HTTP 协议的正确性。如果没有这些注释,结果将取决于客户端请求和服务器的默认行为(在不同的实现中可能不同),这会导致不可预测和不明确的结果。
通过这些注释,我们宣传我们可以生产和消费哪些媒体类型。在检索 (GET) 请求中,客户端应发送 Accept
header 以及他们期望返回的资源的媒体类型。在创建请求(PUT,POST)时,客户端应该发送 Content-Type
header 告诉服务器他们发送的数据是什么媒体类型。如果这些 header 与服务器宣传要处理的内容不匹配,那么客户端将收到错误响应,告诉他们问题出在哪里;使用检索请求和 non-matching Accept
header,响应将是 406 Not Acceptable. With a Create request and a non-matching Content-Type
header, the response will be a 415 Unsupported Media Type.
这就是内容协商的工作原理。为了确保我们的服务器按照客户的期望运行,我们应该声明我们可以在服务器上处理什么。注释就是这样做的。
如您所述,当您离开 @Produces
时,客户告诉您需要更改响应类型。这是因为结果是 Content-Type
响应 header 被设置为 application/octet-stream
,这就是 the answers here 的结论。客户端使用 Content-Type
header 来确定如何处理响应。
最后一个示例是针对检索请求的。如果我们在 Create 端点上离开 @Consumes
,很多不同的事情都会出错。举个例子,我们有一个我们想要接受 JSON 的端点,所以我们创建一个 POJO 来将 JSON 映射到。
@POST
public Response create(Customer customer) {}
要使其正常工作,取决于客户端将请求中的 Content-Type
header 设置为 application/json
。但是如果没有 @Consumes
注释,我们基本上是在宣传这个端点能够接受 any 媒体类型,这太荒谬了。 @Consumes
注释就像守卫说 "If you don't send the right type of data, you cannot pass"。但是由于我们没有守卫,所有的数据都被允许通过,结果是不可预测的,因为根据客户端设置 Content-Type
的内容,我们不知道 MessageBodyReader
1 将处理从实体 body 到 Customer
的转换。如果没有选择正确的 MessageBodyReader
(将 JSON 转换为 POPJO 的那个),那么很可能会导致异常,并且客户端将返回 500 Internal Server Error,这不是与获得 415 不支持的媒体类型一样具体。
1. See chapter 8 and 9 of the Jersey docs。它将解释如何分别使用 MessageBodyReader
和 MessageBodyWriter
将实体主体转换为 Java objects(反之亦然)。