如何从 RESTful API 正确传递错误?

How to correctly deliver errors from a RESTful API?

提问人:jeffery_the_wind 提问时间:7/6/2016 最后编辑:jeffery_the_wind 更新时间:7/6/2016 访问量:3069

问:

我指的是 Github 上的这个项目。因此,这应该是一个用于管理电影租赁服务的 RESTful API。我的意思是它现在在技术上“有效”,但它要做的一件事是将错误消息从内部方法直接传递给客户端。

以以下代码为例:

/*
GET films
*/
get("/films", (req, res) -> {
    try {
        String json_output = get_film_list();
        return json_output;
    } catch (Exception e) {
        return "{\"error\":\"There was an error: " + e.toString().replace("\"","") + "\"}";
    }
});

我们有方法:get_film_list()

public static String get_film_list()  throws SQLException, URISyntaxException{
    Connection connection = ConnectionPool.getDBCP2Connection();
    Statement stmt = connection.createStatement();
    ResultSet rs = stmt.executeQuery("SELECT * FROM films");

    String output = "{\"films\":[";
    int got_result = 0;
    while (rs.next()) {
        output += "{\"id\":\""+rs.getInt(1)+"\",\"name\":\""+rs.getString(2)+"\",\"type\":\""+rs.getInt(3)+"\"},";
        got_result = 1;
    }
    rs.close();
    stmt.close();
    output = output.substring(0, output.length()-1) + "]}";

    if (got_result == 1){
        return output;
    }else{
        throw new SQLException("No films.");
    }
}

因此,错误通过 API 传递给用户。我发现这对开发非常方便。我知道,如果服务器响应包含该属性,则会出现错误,并且它提供了错误消息。我通过代码审查听说这根本不是这样做的方法。我还怀疑也许你应该给出正式的 HTTP 错误或其他东西。但与此同时,我想我希望我的 api 始终返回漂亮的 JSON 格式字符串。error

当用户尚未进行身份验证时,他们将看到以下内容:

{“error”:“请进行身份验证。

我在数据库连接类中创建了一个错误,用户会看到以下内容:

{“error”:“出现错误:java.sql.SQLException:无法加载 JDBC 驱动程序类 'org.postgresql.Drive'“}

因此,我的问题归结为,使用 RESTful API 向用户返回错误消息的正确方法是什么。其中一种使用返回 JSON 数据。

谢谢!

Java JSON API REST 错误报告

评论

4赞 Mr_Thorynque 7/6/2016
Rest协议基于http(Soap并非如此),所以我认为您必须使用http标头使用http错误。但是你总是可以在正文中放一个漂亮的错误json。所以你可以同时做这;)
0赞 Fildor 7/6/2016
“出现错误:java.sql.SQLException:无法加载 JDBC 驱动程序类”org.postgresql.Drive“ - 这正是使用户转到”WTF?“的原因。如果存在 SQLException,用户不感兴趣。他希望被告知“请进行身份验证!”或“这是内部服务器错误。请联系客户服务部。
4赞 GhostCat 7/6/2016
关于代码质量的旁注:请学习 java 编码指南。不要在方法名称中使用“_”。从不。曾。
0赞 fractalwrench 7/6/2016
返回适当的状态代码可能比 JSON 中的 String 消息更有用。例如,大多数开发人员会知道 404 的含义,而“未找到”作为字符串消息则不那么明显。

答:

3赞 Vishal Jumani 7/6/2016 #1

RESTful 服务基于两件事,响应代码和实际响应本身。

好吧,基本上它归结为您要处理的错误。此特定方案意味着找不到任何数据,您将找到处理此方案的不同方法。任何其他错误情况的处理方式都不同

处理此错误的两种方法是

场景 1:

响应代码:200 OK
响应:{}

这意味着没有指定请求的数据(更何况是随请求提供的参数)

场景 2:

响应代码:404 未找到
响应:{“error”:“错误消息”}

但这可能会造成混淆,以表明未找到该服务。但这取决于你如何定义 RESTful API。

据我了解,上述情况是两者的混合,它发出 200 OK,但同时也发出错误消息,这不是这样做的方法。

最好通读 REST 的规则,然后拿出你的 API。

此外,可能值得通过 SWAGGER 或 RAML 记录您的 API,这使得它对使用该服务的人来说很有意义,而无需通过大量代码来理解它。

评论

0赞 jeffery_the_wind 7/6/2016
我一直在使用 Instagram API,这里有一个简短的描述: instagram.com/developer/endpoints 它们总是提供包含 .该代码看起来始终是 HTTP 状态代码。如果不是 200,那么它们也会提供错误消息。你认为这样可以吗?所有代码和错误消息都在 json 格式的字符串中?不确定您是否暗示可以在 json 输出旁边发送 http 响应代码?metacode
0赞 Vishal Jumani 7/7/2016
@jeffery_the_wind:我猜你现在已经有了答案。对不起,我昨天不在身边
0赞 jeffery_the_wind 7/7/2016
嗯,是的,谢谢你,我意识到我不太了解一般的 HTTP 响应,以及 sparkjava 如何处理这些响应。
2赞 Daniel Figueroa 7/6/2016 #2

由于您使用的是 http,因此您应该正确使用 http 状态代码,例如 SQL 异常可能会导致响应代码 ,但您不应该公开实际的堆栈跟踪或异常,至少出于两个原因500 Internal Server Error

  1. api-user 无法使用该错误消息,他无法对它采取行动或采取任何合理的措施来修复它。
  2. 您正在公开应用程序内部,这可能会为具有恶意意图的人提供有价值的信息。

当涉及到实际显示错误时。希望用户可以有某种用途。你几乎可以用任何你认为适合你的api的方式来做到这一点。重要的是 api 是一致的。

我想说的是,您现在给出的响应的主体是可以的,除了当您只是调用时,实际消息可能对目标用户没有任何意义,该信息是为开发人员准备的,并且可能应该被记录下来。toString()Exception

您需要做的是,将异常转换为可用的错误消息并使用 http 状态代码。

2赞 cassiomolin 7/6/2016 #3

在 HTTP 协议之上创建 REST API 时,HTTP 状态代码是指示操作结果的正确方式。除了状态代码外,您还可以返回一条消息,其中包含有关错误的更多详细信息。

在下面找到客户端似乎出错时最常见的错误状态代码:

不要定义自己的状态代码。坚持标准。


返回消息时,HTTP 响应可以如下所示:

HTTP/1.1 404 Not Found
Content-Type: application/json

{ "error" : "Resource not found with the requested identifier" }

评论

0赞 jeffery_the_wind 7/6/2016
将代码反馈回 json 格式的变量中是否可以接受?例如,在 instagram API 中,它们始终提供包含属性(http 状态代码)的属性。instagram.com/developer/endpointsmetacode
1赞 cassiomolin 7/6/2016
@jeffery_the_wind 如果客户端请求的资源找不到,则在 HTTP 响应中返回错误。除此之外,您还可以返回包含 HTTP 状态代码的 JSON。但要保持一致:不要以 HTTP 状态代码和 JSON 形式返回。404 Not Found404200 OK404
1赞 jeffery_the_wind 7/7/2016
非常感谢你帮助我。我想在纠缠了一会儿后我明白了。我想我需要阅读更多关于 sparkjava 如何提供 http 响应的信息。我认为你得到的是,在我的 GET 方法中,它返回一个字符串,在本例中为 JSON 格式,但通过简单地返回一个字符串,它给出了 200 HTTP 响应,但 msg 是错误的。如果用户未经过身份验证,我会发出 .这种方式可能更准确,因为我给出了一个错误代码,然后是我的自定义消息。halt(401, "{\"error\":\"Please Authenticate.\"}");
1赞 cassiomolin 7/7/2016
@jeffery_the_wind 我的建议是:坚持标准,并为每种情况返回最合适的 HTTP 代码。例如,在请求不存在的资源时不要返回 a;A 要好得多。如果经过身份验证的用户无权访问资源,则不要返回 a;A 是这种情况的正确响应。除了状态代码外,还可以返回描述性消息或错误。它将帮助客户了解请求出了什么问题。200 OK404 Not Found 200 OK403 Forbidden4xx
1赞 cassiomolin 7/7/2016
@jeffery_the_wind 如果您需要任何进一步的澄清:)请告诉我