在所有产生JSON的端点上使用@Produces(“ application / json”)是一种好习惯吗?

时间:2018-07-04 08:29:19

标签: java jersey jax-rs

我们开始将Jersey / JAX-RS用于内部REST端点,这些端点被我们的前端代码使用。必须返回结果的端点始终发送JSON对象。

出于调试目的,我们使用firefox restclient扩展名。直到最近,我才输入URL并单击send,然后返回显示为JSON的内容。

但是当我今天早上这样做时,FF扩展名又回来了,并告诉我必须将响应类型更改为二进制(BLOB)。这样做会导致显示编码的字符串而不是JSON。

我可以通过将请求标头(Accept:设置为application/json)来解决此问题。

做更多的研究,我发现了这个question。我的结论是:也许我们应该在所有这些端点中添加@Produces("application/json")

问题:真的那么简单吗?还是有很好的技术理由不这样做?

2 个答案:

答案 0 :(得分:3)

出于Content Negotiation和HTTP协议正确性的考虑,您应该始终声明@Produces@Consumes注释(在类级别或方法级别) 。如果没有这些注释,结果将取决于客户端请求和服务器的默认行为(在不同的实现中可能有所不同),这将导致无法预测和模棱两可的结果。

使用这些注释,我们宣传我们可以产生和消费的媒体类型。在获取(GET)请求时,客户端应发送一个Accept标头,其中包含他们期望返回的资源的媒体类型。并且在创建请求(PUT,POST)时,客户端应发送一个Content-Type头,告诉服务器它们正在发送的数据是哪种媒体类型。如果这些标头与广告服务器要处理的标头不匹配,则客户端将收到错误响应,告诉他们问题出在哪里;带有检索请求和不匹配的Accept标头,响应将是406 Not Acceptable。使用创建请求和不匹配的Content-Type标头,响应将是415 Unsupported Media Type

这是内容协商的工作方式。为了确保我们的服务器行为符合客户的期望,我们应该声明我们可以在服务器上处理的内容。注释就是这样做的。

正如您提到的,当您离开@Produces时,客户端告诉您您需要更改响应类型。这是因为结果是Content-Type响应标头设置为the answers here得出的application/octet-stream。客户端使用Content-Type标头来确定如何处理响应。

最后一个示例是针对“检索”请求的。如果我们在创建端点上放弃了@Consumes,那么很多不同的事情都会出错。例如,我们有一个要接受JSON的端点,因此我们创建一个POJO来将JSON映射到。

@POST
public Response create(Customer customer) {}

要使其正常工作,取决于客户端将请求上的Content-Type标头设置为application/json。但是,如果没有@Consumes批注,我们基本上是在宣传此端点,使其能够接受 any 媒体类型,这简直是荒谬的。 @Consumes注释的作用就像是一个警卫,说“如果没有发送正确的数据类型,就无法通过”。但是,由于我们没有保护措施,因此所有数据都可以通过,因此结果是不可预测的,因为根据客户端将Content-Type设置为的内容,我们不知道MessageBodyReader 1 将处理从实体主体到Customer的转换。如果未选择正确的MessageBodyReader(将JSON转换为POPJO的那个),则很可能会导致异常,并且客户端将返回500 Internal Server Error,该错误不如415不支持的媒体类型。


1。 See chapter 8 and 9 of the Jersey docs。它将说明如何分别使用MessageBodyReaderMessageBodyWriter将实体主体转换为Java对象(反之亦然)。

答案 1 :(得分:1)

  

在所有产生JSON的端点上使用@Produces("application/json")是一种好习惯吗?

如果您的资源方法生成JSON作为资源的表示形式,则应 @Produces(MediaType.APPLICATION_JSON)进行注释。结果,响应将具有一个Content-Type头,指示有效负载的媒体类型。

@Produces批注还用于请求匹配:JAX-RS运行时将Accept标头中发送的媒体类型与{ {3}}注释。


如果您不想注释应用程序中的每个资源方法,则可以注释资源类。这将指示此类中定义的所有方法都必须产生JSON作为资源的表示形式。


@Produces批注中定义的媒体类型指示将由在应用程序中注册的@Produces实例产生的媒体类型。考虑以下示例:

@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实现中完成的。例如,如果您的应用程序使用MessageBodyWriter,则Jackson将用于将Java对象转换为JSON文档。