如何在Cloud Endpoints中返回自定义错误代码?

时间:2015-03-22 22:15:06

标签: java rest google-app-engine exception-handling google-cloud-endpoints

如此处所述https://cloud.google.com/appengine/docs/java/endpoints/exceptions Google Cloud Endpoints仅返回非常有限的http状态代码范围,即:

HTTP 400 BadRequestException
HTTP 401 UnauthorizedException
HTTP 403 ForbiddenException
HTTP 404 NotFoundException (also: Timeout)
HTTP 405
HTTP 408
HTTP 409 ConflictException
HTTP 410
HTTP 412
HTTP 413

Google建议使用现有状态代码返回自定义错误:

“在许多情况下,您可能希望使用常见的HTTP状态代码来指示用户API请求的成功或失败。例如,如果用户尝试检索不存在的实体,则可能希望发送HTTP 404状态代码,说明没有实体存在ID:entityId。 您可以通过抛出端点库提供的异常来发送此类常见HTTP状态代码,如下所示:

String message = "No entity exists with ID: " + entityId;
throw new NotFoundException(message);

在同一份文件中,Google表示:

“任何其他HTTP 4xx代码将作为错误404”

返回

有什么问题?如果找不到我的实体,我会抛出404,但谷歌也会因为几乎任何其他错误而抛出404。

除了401,403和409之外,我可以用它来告诉我的客户端确切的错误是什么(授权,禁止或冲突),我需要回到400和404以获取所有其他状态代码结果是我的客户从来不知道问题究竟是什么。

当然,我可以包含一个人类可读的错误消息,但这是针对服务器代码中出现的RuntimeException,而不是告诉我的客户端它发送的数据有问题。

当然,我也可以使用错误描述的前几位来发送特定于应用程序的错误代码并发送通用400错误请求,但我想这不是应该如何完成的。

任何意见都表示赞赏。如何返回客户端可用于解决特定于应用程序的问题的特定于应用程序的错误代码?

1 个答案:

答案 0 :(得分:1)

阅读以下和其他帖子

我几乎会说Google建议的错误,因为http状态代码和应用程​​序代码之间没有明显区别。两者都发生在不同的层上,客户端无法判断它是否发出错误请求,例如违反合同(例如,调用不存在的端点,本质上是运行时错误),或者传递错误的id(应用程序层)误差)。

文章提出以下解决方案:

  • 使用http错误代码:并不总是如上所述
  • 将应用程序错误添加为自定义响应标头:我不会选择此选项,因为它不会出现在日志中,这会使调试变得困难。
  • 总是返回200并将结果包装在JSON中(如sockets.io所做):端点不可行

我想出了另一种解决方案,我承认这是一种妥协(实际上违反了错误消息),但我认为这是将各个应用程序错误代码最佳地整合到Cloud Endpoints中的方法:

  • 我扩展了400 BadRequestException,因此任何错误消息都以JSON的形式返回。客户端仍然收到http状态代码400,但它收到一个JSON字符串,而不是String错误消息,如下所示:

{     “代码”:400,     “message”:“这是一个人类可读的错误消息。” }

这里我有两个选择:要么我返回代码400,这意味着这是一个BadRequestException,其中客户端实际违反了合同,或者我返回任何其他特定于应用程序的代码,客户端可以轻松解析和处理。

我的ApplicationException看起来像这样(它使用自定义JSONizer,所以它不适合你,但你可以使用JSONObject,GSON,Jackson,等等):

import com.google.api.server.spi.response.BadRequestException;

public class ApplicationException extends BadRequestException {
    private static final int DEFAULT_APPLICATION_CODE = 400; // use this code for all requests without explicit code

    public ApplicationException(int code, String message) {
        super(JsonResponse.build()
                .add("code", code)
                .add("message", message)
                .toString());
    }
    public ApplicationException(String message) {
        super(JsonResponse.build()
                .add("code", DEFAULT_APPLICATION_CODE)
                .add("message", message)
                .toString());
    }
    public ApplicationException(String message, Throwable cause) {
        super(JsonResponse.build()
                .add("code", DEFAULT_APPLICATION_CODE)
                .add("message", message)
                .toString());
    }

}

我没有将我的答案标记为正确,因为如果您认为有更好的方法可以执行此操作,我希望您继续发布更多建议和评论。