我正在构建REST API,但我遇到了一个问题。
似乎设计REST API的公认惯例是,如果请求的资源不存在,则返回404。
但是,对我而言,这会增加不必要的歧义。传统上,HTTP 404与错误的URI相关联。所以实际上我们说“要么你到了正确的地方,但那个特定记录不存在,或在互联网上没有这样的位置!我真的不确定哪个一个......“
考虑以下URI:
http://mywebsite/api/user/13
如果我收到404,那是因为用户13不存在吗?或者是因为我的网址应:
http://mywebsite/restapi/user/13
过去,如果记录不存在,我刚刚返回带有HTTP 200 OK
响应代码的NULL结果。它很简单,在我看来非常干净,即使它不一定是公认的做法。但是有更好的方法吗?
答案 0 :(得分:79)
404只是HTTP响应代码。最重要的是,您可以提供响应正文和/或其他标题,其中包含开发人员将看到的更有意义的错误消息。
答案 1 :(得分:45)
如果资源不存在,请使用404
。请勿将200
空身返回。
这与编程中的undefined
vs空字符串(例如""
)类似。虽然非常相似,但肯定存在差异。
404
表示该URI不存在(就像编程中的未定义变量一样)。使用空体返回200
意味着那里确实存在某些东西,而且现在某些东西是空的(就像编程中的空字符串一样)。
404
并不意味着它是一个“糟糕的URI”。有一些特殊的HTTP代码用于URI错误(例如414 Request-URI Too Long
)。
答案 2 :(得分:16)
与大多数事情一样,“它取决于”。但对我来说,你的做法并不坏,并且不违反HTTP规范本身。但是,让我们清楚一些事情。
首先,URI应该是不透明的。即使它们对人不透明,它们对机器也是不透明的。换句话说,http://mywebsite/api/user/13
,http://mywebsite/restapi/user/13
之间的差异与http://mywebsite/api/user/13
和http://mywebsite/api/user/14
之间的差异相同,即不同的时期不同。所以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,而不会给予太多的帮助。
答案 3 :(得分:10)
404 Not Found 技术上意味着uri目前映射到资源。在您的示例中,我将对http://mywebsite/api/user/13
的请求解释为返回 404 ,以暗示此网址从未映射到资源。对客户来说,这应该是对话的结束。
要解决歧义问题,您可以通过提供其他响应代码来增强API。例如,假设您希望允许客户端向网址http://mywebsite/api/user/13
发出GET请求,您希望告知客户端应使用规范网址http://mywebsite/restapi/user/13
。在这种情况下,您可能需要考虑通过返回 301 Moved Permanently 来发布永久重定向,并在响应的 Location 标头中提供规范URL。这告诉客户端,为了将来的请求,他们应该使用规范网址。
答案 4 :(得分:8)
所以从本质上讲,听起来答案可能取决于请求的形成方式。
如果请求的资源根据对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仍然是正确的(因为这个概念)用户确实退出http://mywebsite/restapi/user/
);因此,可以合理地预期响应为200(具有适当详细的消息),因为称为13的特定用户不存在但URI存在。这样我们就说URI很好,但是数据请求没有内容。
就个人而言,200仍然感觉不对(虽然我之前曾辩称它确实如此)。例如,当发送不正确的ID时,200响应代码(没有详细响应)可能导致不调查问题。
更好的方法是发送204 - No Content
响应。这符合w3c的描述*服务器已经完成了请求但不需要返回实体主体,并且可能想要返回更新的元信息。* 1在我看来,混淆是由维基百科条目引起的说明 204 No Content - 服务器成功处理了请求,但未返回任何内容。 通常用作对成功删除请求的回复。最后一句话具有高度辩论性。考虑没有那句话的情况,解决方案很简单 - 如果实体不存在,只需发送204。甚至有一个参数返回204而不是404,请求已被处理,并且没有返回任何内容!请注意,虽然204并未允许回复正文中的内容
来源
http://en.wikipedia.org/wiki/List_of_HTTP_status_codes 1. http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
答案 5 :(得分:7)
这篇古老而优秀的文章...... http://www.infoq.com/articles/webber-rest-workflow对此有所说明......
404 Not Found - 该服务太懒(或安全),无法给我们提供我们的请求失败的真正原因,但不管原因,我们需要处理它。
答案 6 :(得分:5)
这是一篇非常古老的帖子,但我遇到了类似的问题,我想与你们分享我的经验。
我正在使用其他API构建微服务架构。我有一些其他的GET服务,它们根据请求参数从后端系统收集数据。
我遵循了其余的API设计文档,当没有与查询条件对齐的数据时(例如,选择了零记录),我向客户端发送了带有完美JSON错误消息的HTTP 404.
当没有数据要发送回客户端时,我准备了一个包含内部错误代码等的完美JSON消息,以告知客户端" Not Found"它通过HTTP 404发送回客户端。这很好。
后来我创建了一个rest API客户端类,这是一个隐藏HTTP通信相关代码的简单助手,当我从代码中调用其余的API时,我一直使用这个帮助器。
但我需要编写令人困惑的额外代码,因为HTTP 404有两个不同的功能:
重要提示:我的rest API错误处理程序捕获后端服务中出现的所有异常,这意味着如果出现任何错误,我的其余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");
}
但是,因为我的Java或JavaScript客户端可以接收两种HTTP 404,我需要在HTTP 404的情况下检查响应的正文。如果我可以解析响应主体那么我我确定在没有数据发送回客户端的情况下我得到了回复。
如果我无法解析响应,这意味着我从Web服务器(而不是其他API应用程序)获得了真正的HTTP 404。
令人困惑,客户端应用程序总是需要进行额外的解析来检查HTTP 404的真正原因。
老实说,我不喜欢这个解决方案。这很令人困惑,需要一直向客户添加额外的废话代码。
因此,在这两种不同的场景中我没有使用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 :(得分:1)
统一资源标识符是指向资源的唯一指针。格式不正确的URI不指向资源,因此对其执行GET将不会返回资源。 404表示服务器未找到与Request-URI匹配的任何内容。如果您输入了错误的URI或错误的URI,这是您的问题以及您没有获得资源的原因,无论是HTML页面还是IMG。
答案 8 :(得分:0)
在这种情况下,HTTP 404是REST API响应的响应代码 像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抛出的正确消息
答案 9 :(得分:-1)
这是我们团队最近提出的。
我们使用带有消息正文的 404 Not found
和基于以下理由的 204 No Content
。
如果请求 URI 指示单个资源的位置,我们使用 404 Not found。当请求查询一个 URI 时,我们使用 204 No Content
http://mywebsite/api/user/13
将在用户 13 不存在时返回 404http://mywebsite/api/users?id=13
将返回 204 无内容http://mywebsite/api/users?firstname=test
将返回 204 无内容这里的想法是,“查询路线”预计不会返回任何内容。 无论您选择哪种模式,最重要的是保持一致 - 所以请从您的团队那里获得支持。