在所有生成JSON的端点上使用@Produces(" application / json")是一种好习惯吗? [英] Is it good practice to use @Produces("application/json") on all JSON producing endpoints?

查看:456
本文介绍了在所有生成JSON的端点上使用@Produces(" application / json")是一种好习惯吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们开始使用Jersey / JAX-RS作为我们的前端代码使用的内部REST端点。必须返回结果的端点总是发送JSON对象。

We started using Jersey/JAX-RS for internal REST endpoints that get used by our front-end code. Endpoints that have to return a result, always send JSON objects.

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

For debugging purposes, we are using the firefox restclient extension. Until recently, I would just enter the URL and hit send, and would get back content displayed as JSON.

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

But when I did that this morning, the FF extension comes back and tells me that I have to change the response type to binary (BLOB). Doing so results in displaying an encoded string instead of JSON.

我可以通过设置请求标头来解决这个问题(接受: application / json )。

I could resolve that by setting a request header (Accept: to be application/json).

做了一些研究,我发现了这个问题。我的结论是:我们可能应该将 @Produces(application / json)添加到所有这些端点。

Doing some more research, I came across this question. My conclusion is: probably we should add @Produces("application/json") to all these endpoints.

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

Question: is it really that simple, or are there good technical reasons to not do that?

推荐答案

你应总是宣布 @Produces @Consumes 注释(在类级别或方法级别),用于内容协商和HTTP协议正确性。如果没有这些注释,结果将取决于客户端请求和服务器的默认行为(实现可能会有所不同),这会导致不可预测和模糊的结果。

You should always declare the @Produces and @Consumes annotations (either at the class level or method level) for the purpose of Content Negotiation and HTTP protocol correctness. Without these annotations, the result will be dependent on the client request and the default behavior of the server (which may be different across implementations), which leads to unpredictable and ambiguous results.

通过这些注释,我们宣传我们可以生产和使用的媒体类型。在检索(GET)请求时,客户端应发送 Accept 标头,其中包含他们期望的资源的媒体类型。在创建请求(PUT,POST)时,客户端应发送 Content-Type 标头,告诉服务器他们发送的数据是什么媒体类型。如果这些标头与广告服务器要处理的内容不匹配,那么客户端将收到错误响应,告诉他们问题是什么;如果有一个Retrieve请求和一个不匹配的 Accept 标题,那么响应将是 406 Not Acceptable 。使用Create请求和不匹配的 Content-Type 标头,响应将是 415不支持的媒体类型

With these annotations, we advertise what media types we can produce and consume. On Retrieve (GET) requests, the client should send an Accept header with the media type of the resource they expect back. And on Create requests (PUT, POST), the client should send a Content-Type header telling the server what media type the data is that they are sending. If these headers don't match what the server is advertised to handle, then the client will get error responses back telling them what the problem is; with a Retrieve request and a non-matching Accept header, the response will be a 406 Not Acceptable. With a Create request and a non-matching Content-Type header, the response will be a 415 Unsupported Media Type.

这就是内容协商的工作原理。为了确保我们的服务器像客户期望的那样运行,我们应该声明我们可以在服务器上处理什么。注释就是这样。

This is how content negotiation works. And to make sure our server behaves as the clients expect, we should declare what we can handle on the server. The annotations do just this.

如你所说,当你离开 @Produces 时,客户告诉你你需要改变响应类型。这是因为结果是 Content-Type 响应头设置为 application / octet-stream ,这是什么这里的答案总结。客户端使用 Content-Type 标头来确定如何处理响应。

As you mentioned, when you left off the @Produces, the client told you you needed to change the response type. This is because the result was that the Content-Type response header was set to application/octet-stream, which is what the answers here conclude. Clients use the Content-Type header to determine how to handle the response.

最后一个示例是针对检索的请求。如果我们在Create端点上停止了 @Consumes ,那么很多不同的东西都可能出错。举个例子我们有一个我们想要接受JSON的端点,所以我们创建一个POJO来将JSON映射到。

That last example was for a Retrieve request. If we left off the @Consumes on a Create endpoint, a lot of different things can go wrong. Take for example we have an endpoint that we want to accept JSON, so we create a POJO to map the JSON to.

@POST
public Response create(Customer customer) {}

为此工作,它是依赖于客户端在 application / json 的请求中设置 Content-Type 标头。但是如果没有 @Consumes 注释,我们基本上宣传这个端点是为了能够接受任何媒体类型,这简直太荒谬了。 @Consumes 注释就像一个警卫说如果你没有发送正确类型的数据,你就无法通过。但由于我们没有守卫,所有数据都被允许通过,结果是不可预测的,因为根据客户端设置 Content-Type 的原因,我们不要不知道 MessageBodyReader 1 将处理从实体主体到 Customer 的转换。如果未选择正确的 MessageBodyReader (将JSON转换为POPJO的那个),则很可能会导致异常,客户端将返回500内部服务器错误,与获取415不支持的媒体类型不同。

For this to work, it is dependent on the client setting the Content-Type header on the request to application/json. But without the @Consumes annotation, we are basically advertising this endpoint to be able to accept any media type, which is just ridiculous. The @Consumes annotation acts like a guard saying "If you don't send the right type of data, you cannot pass". But since we don't have the guard, all data is allowed through, and the result is unpredictable, because depending on what the client sets the Content-Type to, we don't know what MessageBodyReader1 will handle the conversion from the entity body to Customer. If the correct MessageBodyReader is not chosen (the one that converts JSON to POPJOs), then most likely it will lead to an exception, and the client will get back a 500 Internal Server Error, which is not as specific as getting a 415 Unsupported Media Type.

1。 请参阅泽西岛文档的第8章和第9章。它将分别使用 MessageBodyReader MessageBodyWriter 来解释实体主体如何转换为Java对象(反之亦然)。 / sub>

1. See chapter 8 and 9 of the Jersey docs. It will explain how entity bodies are converted to Java objects (and vice versa) using MessageBodyReader and MessageBodyWriter, respectively.

这篇关于在所有生成JSON的端点上使用@Produces(" application / json")是一种好习惯吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆