Estou escrevendo um aplicativo Web REST (NetBeans 6.9, JAX-RS, TopLink Essentials) e tentando retornar o código de status JSON e HTTP. Eu tenho código pronto e funcionando que retorna JSON quando o método HTTP GET é chamado do cliente. Essencialmente:
@Path("get/id")
@GET
@Produces("application/json")
public M_機械 getMachineToUpdate(@PathParam("id") String id) {
// some code to return JSON ...
return myJson;
}
Mas também quero retornar um código de status HTTP (500, 200, 204 etc.) junto com os dados JSON.
Eu tentei usar HttpServletResponse
:
response.sendError("error message", 500);
Mas isso fez o navegador pensar que é um 500 "real"; portanto, a página da Web de saída era uma página de erro HTTP 500 normal.
Desejo retornar um código de status HTTP para que meu JavaScript do lado do cliente possa lidar com alguma lógica dependendo dele (por exemplo, exibir o código de erro e a mensagem em uma página HTML). Isso é possível ou os códigos de status HTTP não devem ser usados para isso?
fonte
Respostas:
Aqui está um exemplo:
Dê uma olhada na classe Response .
Observe que você sempre deve especificar um tipo de conteúdo, especialmente se estiver passando vários tipos de conteúdo, mas se todas as mensagens forem representadas como JSON, você pode apenas anotar o método com
@Produces("application/json")
fonte
return Response.status(Response.Status.Forbidden).entity(myPOJO).build();
Works como se fossereturn myPOJO;
, mas com configurações adicionais do código de status HTTP.Existem vários casos de uso para definir códigos de status HTTP em um serviço da Web REST, e pelo menos um não foi suficientemente documentado nas respostas existentes (por exemplo, quando você está usando a serialização JSON / XML auto-mágica usando JAXB e deseja retornar um objeto a ser serializado, mas também um código de status diferente do padrão 200).
Então, deixe-me tentar enumerar os diferentes casos de uso e as soluções para cada um:
1. Código de erro (500, 404, ...)
O caso de uso mais comum em que você deseja retornar um código de status diferente
200 OK
daquele em que ocorre um erro.Por exemplo:
a) Lance uma exceção
Nesse caso, acho que a maneira mais limpa de lidar com o problema é lançar uma exceção. Essa exceção será tratada por um
ExceptionMapper
, que converterá a exceção em uma resposta com o código de erro apropriado.Você pode usar o padrão
ExceptionMapper
que vem pré-configurado com Jersey (e acho que é o mesmo com outras implementações) e lançar qualquer uma das subclasses existentes dejavax.ws.rs.WebApplicationException
. Estes são tipos de exceção predefinidos, pré-mapeados para diferentes códigos de erro, por exemplo:Etc. Você pode encontrar a lista aqui: API
Como alternativa, você pode definir suas próprias exceções e
ExceptionMapper
classes personalizadas e adicionar esses mapeadores a Jersey pela média da@Provider
anotação ( fonte deste exemplo ):Fornecedor :
Nota: você também pode escrever ExceptionMappers para os tipos de exceção existentes que você usa.
b) Use o construtor Response
Outra maneira de configurar um código de status é usar um
Response
construtor para construir uma resposta com o código pretendido.Nesse caso, o tipo de retorno do seu método deve ser
javax.ws.rs.core.Response
. Isso é descrito em várias outras respostas, como a resposta aceita pela desistência e se parece com isso:2. Sucesso, mas não 200
Outro caso em que você deseja definir o status de retorno é quando a operação foi bem-sucedida, mas você deseja retornar um código de sucesso diferente de 200, juntamente com o conteúdo que você retorna no corpo.
Um caso de uso frequente é quando você cria uma nova entidade (
POST
solicitação) e deseja retornar informações sobre essa nova entidade ou talvez a própria entidade, junto com um201 Created
código de status.Uma abordagem é usar o objeto de resposta como descrito acima e definir o corpo da solicitação. No entanto, ao fazer isso, você perde a capacidade de usar a serialização automática para XML ou JSON fornecida pelo JAXB.
Este é o método original que retorna um objeto de entidade que será serializado em JSON por JAXB:
Isso retornará uma representação JSON do usuário recém-criado, mas o status de retorno será 200, não 201.
Agora, o problema é que, se eu quiser usar o
Response
construtor para definir o código de retorno, tenho que retornar umResponse
objeto no meu método. Como ainda retorno oUser
objeto a ser serializado?a) Defina o código na resposta do servlet
Uma abordagem para resolver isso é obter um objeto de solicitação de servlet e definir o código de resposta manualmente, como demonstrado na resposta de Garett Wilson:
O método ainda retorna um objeto de entidade e o código de status será 201.
Observe que, para fazê-lo funcionar, tive que liberar a resposta. Esse é um ressurgimento desagradável do código da API do Servlet de baixo nível em nosso bom recurso JAX_RS e, muito pior, faz com que os cabeçalhos não sejam modificáveis depois disso, porque eles já foram enviados pela conexão.
b) Use o objeto de resposta com a entidade
A melhor solução, nesse caso, é usar o objeto Response e configurar a entidade para ser serializada nesse objeto de resposta. Seria bom tornar o objeto Response genérico para indicar o tipo de entidade de carga útil nesse caso, mas atualmente não é o caso.
Nesse caso, usamos o método criado da classe do construtor Response para definir o código de status como 201. Passamos o objeto de entidade (usuário) para a resposta por meio do método entity ().
O resultado é que o código HTTP é 401 como desejávamos, e o corpo da resposta é exatamente o mesmo JSON que tínhamos antes, quando retornamos o objeto Usuário. Ele também adiciona um cabeçalho de localização.
A classe Response possui vários métodos do construtor para diferentes status (stati?), Como:
Response.accepted () Response.ok () Response.noContent () Response.notAcceptable ()
NB: o objeto hateoas é uma classe auxiliar que desenvolvi para ajudar a gerar URIs de recursos. Você precisará criar seu próprio mecanismo aqui;)
É sobre isso.
Espero que esta longa resposta ajude alguém :)
fonte
flush
fato é sujo.A resposta por herdrewness funcionará, mas modifica toda a abordagem para permitir que um provedor como o Jackson + JAXB converta automaticamente o objeto retornado em algum formato de saída como JSON. Inspirado em uma postagem do Apache CXF (que usa uma classe específica do CXF), encontrei uma maneira de definir o código de resposta que deve funcionar em qualquer implementação do JAX-RS: injete um contexto HttpServletResponse e defina manualmente o código de resposta. Por exemplo, aqui está como definir o código de resposta para
CREATED
quando apropriado.Melhoria: Depois de encontrar outra resposta relacionada , aprendi que é possível injetar a
HttpServletResponse
variável como membro, mesmo para a classe de serviço singleton (pelo menos em RESTEasy) !! Essa é uma abordagem muito melhor do que poluir a API com detalhes de implementação. Seria assim:fonte
@Produces
e não especifique o tipo de mídia na finalResponse.ok
, e você obterá seu objeto de retorno corretamente serializado por JAXB no tipo de mídia apropriado para corresponder à solicitação. (Eu apenas tentei isso com um único método que poderia retornar XML ou JSON: o método em si não precisa mencionar qualquer um, exceto na@Produces
anotação.)MessageBodyWriter
eProvider
permite a negociação de conteúdo implícito, embora pareça o seu exemplo está faltando algum código. Aqui está outra resposta que forneci que ilustra isso: stackoverflow.com/questions/5161466/… #response.setStatus()
. A única maneira de enviar, por exemplo, uma resposta 404 Não encontrada, é definir o código de status da respostaresponse.setStatus(404)
e fechar o fluxo de saídaresponse.getOutputStream().close()
para que o JAX-RS não possa redefinir meu status.response.flushBuffer()
para evitar que a estrutura substituísse meu código de resposta. Não é muito limpo.404 Not Found
, pode ser mais fácil usá-lothrow new NotFoundException()
.Se você deseja manter sua camada de recursos limpa de
Response
objetos, recomendo que você use@NameBinding
e ligue as implementações deContainerResponseFilter
.Aqui está o conteúdo da anotação:
Aqui está a carne do filtro:
E então a implementação em seu recurso simplesmente se torna:
fonte
StatusFilter
com@Status
: você quer necessidade de fornecer um padrão para o de anotaçãovalue
campo, ou declarar um quando anotando a classe (ex:@Status(200)
). Obviamente, isso não é o ideal.Caso deseje alterar o código de status devido a uma exceção, com o JAX-RS 2.0, você pode implementar um ExceptionMapper como este. Isso lida com esse tipo de exceção para todo o aplicativo.
fonte
Se o seu WS-RS precisar gerar um erro, por que não usar apenas o WebApplicationException?
fonte
O JAX-RS possui suporte para códigos HTTP padrão / customizados. Consulte ResponseBuilder e ResponseStatus, por exemplo:
http://jackson.codehaus.org/javadoc/jax-rs/1.0/javax/ws/rs/core/Response.ResponseBuilder.html#status%28javax.ws.rs.core.Response.Status%29
Lembre-se de que as informações JSON são mais sobre os dados associados ao recurso / aplicativo. Os códigos HTTP são mais sobre o status da operação CRUD que está sendo solicitada. (pelo menos é assim que deveria ser nos sistemas REST-ful)
fonte
Achei muito útil criar também uma mensagem json com código repetido, assim:
fonte
Veja o exemplo aqui, ele ilustra melhor o problema e como ele foi resolvido na versão mais recente (2.3.1) do Jersey.
https://jersey.java.net/documentation/latest/representations.html#d0e3586
Basicamente, envolve definir uma exceção personalizada e manter o tipo de retorno como a entidade. Quando houver um erro, a exceção será lançada; caso contrário, você retornará o POJO.
fonte
Response
nela. Basta procurar aCustomNotFoundException
turma e talvez copiá-la para sua postagem.Não estou usando JAX-RS, mas tenho um cenário semelhante em que uso:
fonte
Além disso, observe que, por padrão, Jersey substituirá o corpo da resposta no caso de um código http 400 ou mais.
Para obter sua entidade especificada como o corpo da resposta, tente adicionar o seguinte init-param ao seu Jersey no seu arquivo de configuração web.xml:
fonte
O código a seguir funcionou para mim. Injetando o messageContext via setter anotado e definindo o código de status no meu método "add".
fonte
Expandindo a resposta da Nthalk com o Microprofile OpenAPI, você pode alinhar o código de retorno à sua documentação usando a anotação @APIResponse .
Isso permite marcar um método JAX-RS como
Você pode analisar essa anotação padronizada com um ContainerResponseFilter
Uma ressalva ocorre quando você coloca várias anotações no seu método, como
fonte
Estou usando o jersey 2.0 com leitores e escritores do corpo da mensagem. Eu tive meu tipo de retorno de método como uma entidade específica que também foi usada na implementação do gravador do corpo da mensagem e estava retornando o mesmo pojo, um SkuListDTO. @GET @Consumes ({"application / xml", "application / json"}) @Produces ({"application / xml", "application / json"}) @Path ("/ skuResync")
tudo que mudei foi isso, deixei a implementação do gravador sozinha e ainda funcionava.
fonte