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

标签 java rest google-app-engine exception 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,但 Google 也会针对几乎所有其他错误抛出 404。

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

当然,我可以包含一条人类可读的错误消息,但这意味着服务器代码中发生的 RuntimeException,而不是告诉我的客户端它发送的数据存在问题。

当然,我还可以使用错误描述的前几位来发送应用程序特定的错误代码并发送通用的 400 错误请求,但我想这不应该这样做。

欢迎任何意见。如何返回应用程序特定的错误代码,您的客户端可以使用该代码来解决特定于应用程序的问题?

最佳答案

已阅读以下内容和其他帖子

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

文章提出了以下解决方案:

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

我提出了另一种解决方案,我承认这是一种妥协(事实上,违反了错误消息),但我认为这是将单个应用程序错误代码集成到云端点中的最合适的方法:

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

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

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

我的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());
    }

}

我没有将我的答案标记为正确,因为如果您认为有更好的方法可以做到这一点,我希望您继续发布进一步的建议和评论。

关于java - 如何在 Cloud Endpoints 中返回自定义错误代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29200490/

相关文章:

java - spring boot,jetty,liquibase,jar,找不到 liquibase.logging.Logger 的实现

web-services - 将 CSRF 保护与 RESTful API 相结合的可行技术有哪些?

php - GET 与 POST 最佳实践

java - 如何从 JSP 文件中删除实体(使用 Google App Engine 的 Java)

python - App Engine channel API 不返回任何消息

google-app-engine - 有什么工具可以备份/恢复 Google Datastore 实体吗?

java - Android setOnClickListener 不起作用

java.sql.SQLException : ORA-00904

java - 使用 JavaMail 发送电子邮件,由于 "Connection refused"而收到 "too many connections"- 为什么?

c# - 如何使这段代码变干?