首页 文章

REST API 404:错误的URI或缺少资源?

提问于
浏览
157

我正在构建REST API,但我遇到了一个问题 .

似乎在设计REST API时接受的做法是,如果请求的资源不存在,则返回404 .

但是,对我来说,这增加了不必要的模糊性 . 传统上,HTTP 404与错误的URI相关联 . 所以实际上我们说“要么你到了正确的地方,但那个特定的记录不存在, or 我真的不确定哪一个......”

考虑以下URI:

http://mywebsite/api/user/13

如果我得到404,那是因为用户13不存在吗?或者是因为我的网址应该是:

http://mywebsite/restapi/user/13

在过去,我刚刚使用 HTTP 200 OK 响应代码返回NULL结果,如果记录简单,并且在我看来非常干净,即使它不一定是公认的做法 . 但是有更好的方法吗?

9 回答

  • 72

    统一资源标识符是指向资源的唯一指针 . 形式不佳的URI并不指向资源并因此对其执行GET将不会返回资源 . 404表示服务器未找到与Request-URI匹配的任何内容 . 如果您输入了错误的URI或错误的URI,这是您的问题以及您没有获得资源的原因,无论是HTML页面还是IMG .

  • 38

    404只是HTTP响应代码 . 最重要的是,您可以提供响应正文和/或其他 Headers ,其中包含开发人员将看到的更有意义的错误消息 .

  • 1

    Use 404 if the resource does not exist. Don't return 200 with an empty body.

    This is akin to undefined vs empty string (e.g. "") in programming. While very similar, there is definitely a difference.

    404 表示该URI没有任何内容(如编程中的未定义变量) . 使用空体返回 200 意味着那里确实存在某些东西,而且现在某些东西是空的(就像编程中的空字符串一样) .

    404 并不意味着它是"bad URI" . 有一些特殊的HTTP代码用于URI错误(例如 414 Request-URI Too Long ) .

  • 5

    和大多数事情一样,"it depends" . 但对我来说,你的实践并不差,并且不违反HTTP规范本身 . 但是,让我们清楚一些事情 .

    首先,URI 's should be opaque. Even if they'对人不透明,对机器不透明 . 换句话说, http://mywebsite/api/user/13http://mywebsite/restapi/user/13 之间的差异与 http://mywebsite/api/user/13 和_1665102之间的差异相同,即不同的时期不是同一个 . 所以404将完全适合 http://mywebsite/api/user/14 (如果没有这样的用户)但不一定是唯一合适的响应 .

    您还可以返回空200响应或更明确地返回204(无内容)响应 . 这会向客户传达别的东西 . 这意味着 http://mywebsite/api/user/14 确定的资源没有内容或基本上没有 . 它确实意味着有这样的资源 . 但是,它并不一定意味着您声称在ID为14的数据存储中存在一些用户 . 这是您的私人关注点,而不是发出请求的客户端的关注点 . 因此,如果以这种方式对资源进行建模是有意义的,那就继续吧 .

    为您的客户提供信息会使他们更容易猜出合法的URI,这会带来一些安全隐患 . 在未命中而不是404时返回200可能会给客户一个至少 http://mywebsite/api/user 部分是正确的线索 . 恶意客户端可以继续尝试不同的整数 . 但对我来说,恶意客户端无论如何都能猜到 http://mywebsite/api/user 部分 . 更好的补救措施是使用UUID . 即 http://mywebsite/api/user/3dd5b770-79ea-11e1-b0c4-0800200c9a66 优于 http://mywebsite/api/user/14 . 这样做,你可以使用你的技术返回200,而不会给予太多 .

  • 9

    404 Not Found 技术上意味着uri当前没有映射到资源 . 在您的示例中,我将请求解释为 http://mywebsite/api/user/13 ,该请求返回 404 以暗示此URL始终未映射到资源 . 对客户来说,这应该是对话的结束 .

    要解决模棱两可的问题,您可以通过提供其他响应代码来增强API . 例如,假设您希望允许客户端向URL发送GET请求 http://mywebsite/api/user/13 ,您希望传达客户端应使用规范URL http://mywebsite/restapi/user/13 . 在这种情况下,您可能需要考虑通过返回301 Moved Permanently来发出永久重定向,并在响应的Location标头中提供规范URL . 这告诉客户端,对于将来的请求,他们应该使用规范URL .

  • 16

    这篇古老而优秀的文章...... http://www.infoq.com/articles/webber-rest-workflow这样说了......

    404 Not Found - 服务太懒(或安全),无法给我们一个真正的原因,我们的请求失败了,但无论什么原因,我们都需要处理它 .

  • 0

    所以从本质上讲,听起来答案可能取决于请求的形成方式 .

    如果请求的资源根据对 http://mywebsite/restapi/user/13 的请求构成URI的一部分并且用户13不存在,那么404可能是合适且直观的,因为URI代表了不存在的用户/实体/文件/等 . 对于使用GUID http://mywebsite/api/user/3dd5b770-79ea-11e1-b0c4-0800200c9a66 和上面的api / restapi参数的更安全技术,情况也是如此 .

    但是,如果请求的资源ID包含在请求标头中[包括您自己的示例],或者确实在URI中作为参数包含,例如 http://mywebsite/restapi/user/?UID=13 那么URI仍然是正确的(因为USER的概念确实退出 http://mywebsite/restapi/user/ );因此,可以合理地预期响应为200(具有适当详细的消息),因为称为13的特定用户不存在但URI存在 . 这样我们就说URI很好,但是对数据的请求没有内容 .

    就个人而言,200仍然感觉不对(虽然我以前认为它确实如此) . 例如,当发送不正确的ID时,200响应代码(没有详细响应)可能导致不调查问题 .

    更好的方法是发送 204 - No Content 响应 . 这符合w3c的描述*服务器已经完成了请求但不需要返回实体主体,并且可能想要返回更新的元信息 . * 1在我看来,混淆是由维基百科条目引起的204 No Content - 服务器成功处理了请求,但未返回任何内容 . Usually used as a response to a successful delete request . 最后一句话是高度辩论的 . 考虑没有那句话的情况,解决方案很简单 - 如果实体不存在,只需发送204 . 甚至有一个参数返回204而不是404,请求已被处理,并且没有返回任何内容!请注意,204不允许回复正文中的内容

    来源

    http://en.wikipedia.org/wiki/List_of_HTTP_status_codes 1. http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

  • 7

    这是一个非常古老的帖子,但我遇到了类似的问题,我想与你们分享我的经验 .

    我正在使用其他API构建微服务架构 . 我有一些休息的GET服务,它们根据请求参数从后端系统收集数据 .

    我遵循了其余的API设计文档,当没有与查询条件对齐的数据时(例如,选择了零记录),我向客户端发送了带有完美JSON错误消息的HTTP 404 .

    当没有数据发送回客户端时,我准备了一个带有内部错误代码等的完美JSON消息,以通知客户端“未找到”的原因,并通过HTTP 404将其发送回客户端 . 工作良好 .

    后来我创建了一个rest API客户端类,它是一个隐藏HTTP通信相关代码的简单帮助器,当我从代码中调用其余的API时,我一直使用这个帮助器 .

    但是我需要编写令人困惑的额外代码,因为HTTP 404有两个不同的功能:

    • 真正的HTTP 404,当其余API在给定的URL中不可用时,它由运行其余API应用程序的应用程序服务器或Web服务器抛出
      当数据库中没有基于查询where条件的数据时,
    • 客户端也会返回HTTP 404 .

    重要提示:我的rest API错误处理程序捕获后端服务中出现的所有异常,这意味着如果出现任何错误,我的rest API将始终返回带有消息详细信息的完美JSON消息 .

    这是我的客户端帮助程序方法的第一个版本,它处理两个不同的HTTP 404响应:

    public static String getSomething(final String uuid) {
        String serviceUrl = getServiceUrl();
        String path = "user/" + , uuid);
        String requestUrl = serviceUrl + path;
        String httpMethod = "GET";
    
        Response response = client
                .target(serviceUrl)
                .path(path)
                .request(ExtendedMediaType.APPLICATION_UTF8)
                .get();
    
        if (response.getStatus() == Response.Status.OK.getStatusCode()) {
            // HTTP 200
            return response.readEntity(String.class);
        } else {
            // confusing code comes here just because
            // I need to decide the type of HTTP 404...
    
            // trying to parse response body
            try {
                String responseBody = response.readEntity(String.class);
                ObjectMapper mapper = new ObjectMapper();
                ErrorInfo errorInfo = mapper.readValue(responseBody, ErrorInfo.class);
    
                // re-throw the original exception
                throw new MyException(errorInfo);
    
            } catch (IOException e) {
                // this is a real HTTP 404
                throw new ServiceUnavailableError(response, requestUrl, httpMethod);
            }
    
        // this exception will never be thrown
        throw new Exception("UNEXPECTED ERRORS, BETTER IF YOU DO NOT SEE IT IN THE LOG");
    }
    

    BUT ,因为我的Java或JavaScript客户端可以接收两种HTTP 404,我需要在HTTP 404的情况下检查响应的主体 . 如果我可以解析响应主体,那么我确信我回复了有响应的地方没有数据要发送回客户端 .

    如果我无法解析响应,这意味着我从Web服务器(而不是其他API应用程序)获得了真正的HTTP 404 .

    它是如此令人困惑,客户端应用程序总是需要额外的解析来检查HTTP 404的真正原因 .

    老实说,我不喜欢这个解决方案 . 这很令人困惑,需要一直向客户添加额外的废话代码 .

    因此,在这两种不同的场景中我没有使用HTTP 404,而是决定我将执行以下操作:

    • 我不再使用HTTP 404作为我的休息应用程序中的响应HTTP代码 .

    • 我将使用HTTP 204(无内容)而不是HTTP 404 .

    在这种情况下,客户端代码可以更优雅:

    public static String getString(final String processId, final String key) {
        String serviceUrl = getServiceUrl();
        String path = String.format("key/%s", key);
        String requestUrl = serviceUrl + path;
        String httpMethod = "GET";
    
        log(requestUrl);
    
        Response response = client
                .target(serviceUrl)
                .path(path)
                .request(ExtendedMediaType.APPLICATION_JSON_UTF8)
                .header(CustomHttpHeader.PROCESS_ID, processId)
                .get();
    
        if (response.getStatus() == Response.Status.OK.getStatusCode()) {
            return response.readEntity(String.class);
        } else {
            String body = response.readEntity(String.class);
            ObjectMapper mapper = new ObjectMapper();
            ErrorInfo errorInfo = mapper.readValue(body, ErrorInfo.class);
            throw new MyException(errorInfo);
        }
    
        throw new AnyServerError(response, requestUrl, httpMethod);
    }
    

    我认为这可以更好地处理这个问题 .

    如果您有更好的解决方案,请与我们分享 .

  • 7

    对于这种情况,HTTP 404是来自REST API Like 400,401,404,422不可处理实体的响应的响应代码

    使用异常处理来检查完整的异常消息 .

    try{
      // call the rest api
    } catch(RestClientException e) {
         //process exception
         if(e instanceof HttpStatusCodeException){
            String responseText=((HttpStatusCodeException)e).getResponseBodyAsString();
             //now you have the response, construct json from it, and extract the errors
             System.out.println("Exception :" +responseText);
         }
    
    }
    

    此异常块为您提供REST API抛出的正确消息

相关问题