如何在REST客户端上捕获异常?

时间:2014-05-20 17:58:53

标签: java web-services rest

我已经使用Jersey实现了其他Web服务,并且每当服务器端发生异常时,客户端都会获得通用HTTP 500内部服务器错误,而不再有真正异常的信息。我发现人们通常在服务器端捕获任何异常,然后抛出WebApplicationException,但即使这样,客户端仍然会获得通用的HTTP 500内部服务器错误。

这是我的网络服务:

@PUT
@Produces(MediaType.APPLICATION_XML)
@Consumes(MediaType.APPLICATION_XML)
@Path("/transmitir")
public WrapperTransmissaoRetorno receber(WrapperTransmissao wrapperRecepcao) {
    WrapperTransmissaoRetorno retorno = new WrapperTransmissaoRetorno();
    retorno.setCodigoMaster(new Random().nextInt());
    retorno.setDataRetorno(new Date());
    if(true){
        throw new WebApplicationException("Este pau eh bem graudo");
    }
    return retorno;
}

这是调用客户端的代码:

try {
    WsTransmissaoCliente client = new WsTransmissaoCliente();
    WrapperTransmissao wrapperRecepcao = new WrapperTransmissao();

    Transferencia transferencia = new Transferencia();
    transferencia.setCodigoTabela(23);
    transferencia.setCodigoTransferencia(56);
    transferencia.setDataRetorno(new Date());
    transferencia.setDataTransmissao(new Date(System.currentTimeMillis()+3000000));
    transferencia.setNomeTabela("CUPOM");
    transferencia.setTipoOperacao(TipoOperacao.UPDATE);
    wrapperRecepcao.setTransferencia(transferencia);

    Jumento jumento = new Jumento();
    jumento.setIdade(24);
    jumento.setNome("José");
    wrapperRecepcao.setObjeto(jumento);
//        Cabrito cabrito = new Cabrito();
//        cabrito.setAltura(56);
//        cabrito.setPeso(120.0);
//        wrapperRecepcao.setObjeto(cabrito);
    WrapperTransmissaoRetorno retorno = client.transmitir(wrapperRecepcao);
    System.out.println("Retorno do WS: "+retorno);
} catch (Exception e) {
    WebApplicationException exx = (WebApplicationException) e;
    exx.printStackTrace();
}

如何避免这种情况并获得真正的异常?或者至少是消息?

更新 这是我发送的对象作为回复:

package br.atualy.integracaocheckout.wrappers;

import java.util.Date;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class WrapperTransmissaoRetorno {
    private Date dataRetorno;
    private Integer codigoMaster;

    public Date getDataRetorno() {
        return dataRetorno;
    }

    public void setDataRetorno(Date dataRetorno) {
        this.dataRetorno = dataRetorno;
    }

    public Integer getCodigoMaster() {
        return codigoMaster;
    }

    public void setCodigoMaster(Integer codigoMaster) {
        this.codigoMaster = codigoMaster;
    }

    @Override
    public String toString() {
        return "WrapperRecepcaoRetorno{" + "dataRetorno=" + dataRetorno + ", codigoMaster=" + codigoMaster + '}';
    }
}

更新2 这是客户:

import br.atualy.integracaocheckout.wrappers.WrapperTransmissao;
import br.atualy.integracaocheckout.wrappers.WrapperTransmissaoRetorno;
import javax.ws.rs.ClientErrorException;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.WebTarget;

public class WsTransmissaoCliente {
    private final WebTarget webTarget;
    private final Client client;
    private static final String BASE_URI = "http://localhost:8080/IntegracaoCheckout/webresources";

    public WsTransmissaoCliente() {
        client = javax.ws.rs.client.ClientBuilder.newClient();
        webTarget = client.target(BASE_URI).path("transmissao");
    }

//    public String receber() throws ClientErrorException {
//        WebTarget resource = webTarget;
//        resource = resource.path("receber");
//        return resource.request(javax.ws.rs.core.MediaType.APPLICATION_XML).get(String.class);
//    }

    public WrapperTransmissaoRetorno transmitir(WrapperTransmissao requestEntity) throws ClientErrorException {
        return webTarget.path("transmitir")
                .request(javax.ws.rs.core.MediaType.APPLICATION_XML)
                .put(javax.ws.rs.client.Entity.entity(requestEntity, javax.ws.rs.core.MediaType.APPLICATION_XML), WrapperTransmissaoRetorno.class);
    }

    public void close() {
        client.close();
    }

}

4 个答案:

答案 0 :(得分:2)

通常,最好将方法声明为返回Response对象而不是用户定义的类型,并将数据设置为实体。然后,如果您想表明发生了异常,您可以将该异常作为您要返回的Response的实体传递。

e.g。

@GET
@Path("/foo")
public Response getFoo() {
    try {
        // do stuff
        return Response.ok(someData).build();
    } catch (Exception e) {
        return Response.serverError().entity(e).build();
    }
}

您会注意到,这样您实际上不会从您的方法中抛出异常,而是返回显式的500响应,并将异常作为实体。通过这种方式,您仍然可以从代码中抛出异常,但它们可以很好地处理。

修改

我不确定您的客户端包装器代码在做什么,但您可以使用正常的REST客户端将预期的响应数据类型传递到您的调用中:

    Client client = ClientBuilder.newClient();
    WebTarget target = client.target("http://foo.com/foo");
    String response = target.request().get(String.class);

或者您也可以使用Response方法将其从readEntity()中删除:

    Client client = ClientBuilder.newClient();
    WebTarget target = client.target("http://foo.com/foo");
    Response response = target.request().get();
    String entity = response.readEntity(String.class);

听起来你需要做的就是检查返回代码,然后根据返回的代码将实体解析为WrapperTransmissaoRetornoWebApplicationException

    Response response = client.transmitir(wrapperRecepcao);

    if (response.getStatus() == Response.Status.OK.getStatusCode()) { // 200
        WrapperTransmissaoRetorno retorno = response.readEntity(WrapperTransmissaoRetorno.class);
        // do stuff
    } else  if (response.getStatus() == Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()) { // 500
        WebApplicationException e = response.readEntity(WebApplicationException.class);
        // do stuff
    } // etc for other response codes

答案 1 :(得分:2)

如果使用jawax.ws.rs.core.Response对象。

SERVER :: 如果发生异常/失败,请将其设置为:

// do stuff 
// here e.getMessage() can be custom failure message too
response = Response.serverError().entity(e.getMessage()).build();

// return response object
return response;

CLIENT :: 在客户端检查以下内容:

if(response != null && reponse.getStatus() == Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()) {
   String serverErrorMsg = response.readEntity(String.class);
   throw new Exception(serverErrorMsg);
}

答案 2 :(得分:1)

在webapplication excemption中使用响应对象。它应该工作。

来自java docs:

WebApplicationException(String message)           使用空白消息和默认HTTP状态代码500构建新实例。

这是一条空白信息。我自己还没试过。我想这就是问题所在。

https://jersey.java.net/apidocs/2.6/jersey/javax/ws/rs/WebApplicationException.html

答案 3 :(得分:-1)

即使在所有建议之后我也无法将异常抛给客户端。 所以我所做的是将一个String属性放在我的返回类中,所以当服务器端发生异常时,这个String将包含异常消息,我可以在客户端上获取它。