【问题标题】:Handling exception in Java RestClient在 Java RestClient 中处理异常
【发布时间】:2016-10-20 13:09:59
【问题描述】:

我需要编写一个返回特定对象的多个应用程序使用的 RestClient。 如果出现错误请求(400),我想建议调用者应用消息错误和状态代码。 我想知道使用 code 和 message 属性抛出托管异常是否是一种好的行为,以便从调用者代码中正确捕获。 像这样的:

RestClient.java

ClientResponse response;
try {
    response = client.resource(requestURI).queryParams(queryParams)
            .type(MediaType.APPLICATION_JSON)
            .accept(MediaType.APPLICATION_JSON)
            .post(ClientResponse.class, richiesta);

    boolean output =  response.getStatus() == Response.Status.NO_CONTENT.getStatusCode();

    if (!output && response.getStatus() == Response.Status.BAD_REQUEST)
        throw new RestClientRuntimeException(response.getStatus, response.getEntity(String.class));

} catch (ClientHandlerException e) {
    throw new RestClientRuntimeException(e);
} catch (UniformInterfaceException e) {
    throw new RestClientRuntimeException(e);
}

来电应用

try 
{

    boolean output = restClient.method()

} catch (RestClientRuntimeException e) {

    // read exception status and message entity

}

这是一个好习惯吗?

【问题讨论】:

  • 我认为你搞错了:客户端永远不会从你的服务器代码中看到任何 Java 异常。要使客户端可以使用它,您必须将其添加到 HTTP 响应中或将其放入 HTTP 响应代码 (400)。
  • 为什么不呢? if (!output && response.getStatus() == Response.Status.BAD_REQUEST) throw new RestClientRuntimeException(response.getStatus, response.getEntity(String.class));

标签: java rest


【解决方案1】:

您的问题有几个方面。让我们分别考虑:

我应该将http错误代码翻译成异常吗?

是的,您应该将错误代码转换为异常。例外很好(当然,如果使用正确的话)。他们将幸福的道路与例外情况分开。如果您不使用异常而是返回代码,您的调用者需要检查该返回代码。如果你调用几个方法,你会得到一些令人讨厌的级联 if:

if (service1.method1() == NO_ERROR) {
    if (service2.method2() = NO_ERROR) {
        if (service3.method2() = NO_ERROR) {
            ...
        } else {
            ...
        }
    } else {
        ...
    }
} else {
    ...
}

此外,如果您有多个层(几乎可以肯定有),则需要在每个层级再次执行此操作。这里的例外情况要好得多。他们让您先编码(并阅读!)漂亮而干净的快乐之路,然后 您可以担心 catch 块中的异常。这样更容易写,也更容易阅读。

我应该使用检查异常吗?

这可能会变得非常虔诚。有些人认为检查异常是个好主意,有些人认为它们是邪恶的。我不想在这里详细讨论。就是这样:你想强迫你的调用者考虑那个特殊的例外吗?调用者是否总是或至少在绝大多数情况下有一种方法来处理该异常?

如果您得出的结论是调用者只能记录异常并自行失败,那么您应该避免使用受检异常。这使调用者代码更清晰。无意义的 try..catch 块没有用,只是为了让编译器开心。

说到 REST:在 500 的情况下,很可能没有机会恢复。如果你得到一个 405,你很可能有一个错误,也没有办法恢复。如果您收到 409 冲突,其中包含有关如何解决冲突的一些特殊信息,则可能有一种很好的方法来处理该问题(取决于您的要求)。在这种情况下,您可以考虑检查异常。

我应该将响应代码存储在异常中吗?

当您使用通用 RestClientRuntimeExceptions 并让您的调用者查询响应代码时,那么您的调用者显然与这是一个 REST 调用相关联。如果您正在编写可以查询任意 REST API 的通用 REST 客户端,则可以这样做。在这种情况下没有问题。

但是您已经在使用通用库(我猜是泽西岛)。那么将通用 API 包装在通用 API 周围有什么意义呢?可能有一些原因(例如,评估一些内部使用的标头参数),但您应该考虑一下这是否合理。

也许您想编写一个特定于应用程序的 REST 客户端,即反序列化特定于应用程序的表示类 (DTO) 的客户端。在这种情况下,您不应使用通用异常,而应使用特定于应用程序的异常。如果您使用特定于应用程序的异常,您的调用者不会与这是一个 REST 调用耦合。也许将来会出现一种很酷的新技术,您需要改变您的客户。如果您使用通用异常并让调用者评估响应代码,调用者也需要更改。但是如果你使用特定于应用程序的异常,这个接口会更加稳定。调用者甚至不需要知道存在诸如 REST 之类的东西。当您分离关注点时,这使得调用者代码更简单且更易于维护。

我应该把一个休息客户端放到一个罐子里吗?

我知道你没有问过这个问题。但也许你应该这样做。为任意客户端提供一个带有 Jersey 依赖项的 rest-client jar(在我看来,你就是这样做的)起初看起来不错,但会让你在依赖项上遇到真正的麻烦。如果您不相信,我可以详细解释,但让我们在单独的问题中讨论。

【讨论】:

【解决方案2】:

由于您的成功响应是 JSON,我也会将错误响应建模为 JSON。

例如,考虑以下从 POJO 序列化的 JSON,例如 ErrorMessage.java,具有相应的字段。

{
  "statusCode": 400,
  "errorMessage": "Bad Request",
  "errorDetails": "<details here>"
}

既然是 HTTP,最好根据 HTTP 状态码来传达错误码。如果状态码成功,errorMessageerrorDetails 可以为空。

【讨论】:

    【解决方案3】:

    你为什么不检查HTTP status code family

    除了400 之外的其他错误可能会发生。如果您测试状态代码系列,您可以全部捕获:

    switch (response.getStatusInfo().getFamily()) {
    
    case CLIENT_ERROR:
        // It's a client error
        // You can throw an exception
        break;
    
    case SERVER_ERROR:
        // It's a server error
        // You can throw an exception
        break;
    
    default:
        break;
    }
    

    【讨论】:

      【解决方案4】:

      恕我直言,至少对于 400 状态代码有自定义异常是一个好习惯,因为这意味着发送了格式错误的数据。

      比起抛出未检查的异常并捕获它们,检查的异常更合适。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-09-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-16
        • 1970-01-01
        相关资源
        最近更新 更多