对于有效请求但空数据,正确的REST响应代码是什么?

例如,你为users/9运行一个GET请求,但是没有id为#9的用户。 哪个是最佳响应码?< / p >
  • 200好了
  • 202年接受
  • 204无内容
  • 400错误请求
  • 404未找到
384035 次浏览

在以前的项目中,我使用了404。如果没有用户9,则没有找到对象。因此404 Not Found是合适的。

如果对象存在,但没有数据,则为204 no Content。我认为在你的情况下,对象确实存在

TL;DR:使用404

看到这个博客。这解释得很好。

博客对204的评论摘要:

  1. 204 No Content作为浏览器的响应代码并不是特别有用(尽管根据HTTP规范,浏览器确实需要将其理解为“不改变视图”的响应代码)。
  2. 204 No Content 然而,对于ajax web服务非常有用,它可能想要表明成功而不需要返回一些东西。(特别是在像DELETE或__abc2这样不需要反馈的情况下)。

因此,你的问题的答案是在你的情况下使用404204是一个专门的响应代码,你不应该经常返回到浏览器来响应GET

其他响应代码甚至比204404更不合适:

  1. 200应该与你成功获取的内容一起返回。当你取回的实体不存在时不合适。
  2. 202用于当服务器已经开始处理一个对象,但该对象还没有完全准备好。这里肯定不是这样。你还没有开始,也不会开始构造用户9来响应GET请求。这打破了所有的规则。
  3. 400用于响应格式不佳的HTTP请求(例如格式错误的HTTP报头,不正确的段顺序等)。这几乎肯定可以由您使用的任何框架来处理。除非您从头开始编写自己的服务器,否则不应该处理这些问题。编辑: 更新的rfc现在允许400用于语义无效的请求。
维基百科的HTTP状态码的描述特别有用。 你也可以看到定义详见HTTP/1.1 RFC2616文档www.w3.org

如果期望资源存在,但它可能是空的,我认为它可能更容易得到一个200 OK的表示,表明这个东西是空的。

因此,我宁愿让/things返回一个带有{"Items":[]}的200 OK,而不是一个没有任何内容的204,因为这样,一个包含0项的集合可以被视为一个包含一个或多个项目的集合。

我将把204 No Content留给put和delete,在这种情况下,可能真的没有有用的表示。

在/thing/9不存在的情况下,404是合适的。

我强烈反对404,而支持204或200的空数据。或者至少应该使用带有404的响应实体。

请求被接收并正确地处理了——它确实触发了服务器上的应用程序代码,因此不能真正地说它是客户机错误,因此整个客户机错误代码(4xx)类是不合适的。

更重要的是,404的发生有很多技术原因。例如,应用程序在服务器上被暂时停用或卸载,代理连接问题等等。

当然,这种情况下存在5xx错误类,但实际上,受影响的中间件组件通常无法知道错误在它们这一边,然后只是假设错误在客户端,然后响应404而不是500/503。

因此,仅基于状态代码,客户端无法区分意味着“空结果集”的404;404表示“有严重错误,请将此错误报告给运维团队”。

这可能是致命的:想象一下,您公司的会计服务列出了所有应获得年度奖金的员工。不幸的是,当它被调用时,它返回404。这是否意味着没有人应该得到奖励,或者应用程序目前正在进行新的部署,404实际上来自它应该安装到的tomcat,而不是应用程序本身?这两种场景产生相同的状态码,但它们的含义根本不同。

→对于需要知道所请求的资源不存在而不是暂时不可访问的应用程序来说,没有响应实体的404几乎是行不通的。

此外,许多客户端框架通过抛出异常来响应404,而不询问进一步的问题。这迫使客户端开发人员捕获异常,对其进行评估,然后基于此决定是否将其记录为由监视组件捕获的错误,或者是否忽略它。这对我来说也不太好。

404相对于204的优点是,它可以返回一个响应实体,其中可能包含一些关于为什么没有找到所请求的资源的信息。但如果这确实是相关的,那么人们也可以考虑使用200 OK响应,并设计系统,在有效载荷数据中允许错误响应。 或者,也可以使用404响应的有效负载将结构化信息返回给调用者。如果他收到一个html页面,而不是他可以解析的XML或JSON,那么这是一个很好的指标,技术上出了问题,而不是“没有结果”。从调用者的角度来看可能是有效的回复。或者可以使用HTTP响应头

尽管如此,我还是更喜欢204或200的空白回复。这样,请求的技术执行状态就与请求的逻辑结果分开了。2xx的意思是“技术执行ok,这就是结果,处理它”。

我认为在大多数情况下,应该让客户来决定一个空的结果是否可以接受。通过返回404而不返回响应实体(尽管技术执行正确),客户端可能决定将根本不是错误的情况视为错误。

另一个快速类比:返回404“没有结果”;类似于如果SQL查询没有返回结果就抛出DatabaseConnectionException。它可以完成工作,但是有很多可能的技术原因会抛出相同的异常,然后会被误认为是有效的结果。它使用错误机制来传递有效的结果。

另一个角度:从操作的角度来看,404可能是有问题的。由于它可能表示连接问题,而不是有效的服务响应,因此我不希望“有效性”的数量波动;我的指标/仪表板中的404可能隐藏了真正的技术问题(例如请求路由中的某个错误配置的代理),应该进行调查和修复。 一些api甚至使用404而不是401/403(例如gitlab就是这样做的)来隐藏请求URI是有效的,但请求缺乏访问它的授权的信息,这进一步加剧了这一点。在这种情况下,404也应该被视为技术错误,而不是有效的“资源未找到”。结果。< / p > 编辑:哇,这引起了很多争议。这里有另一个反对404的论点:严格地从HTTP规范(RFC7231)的角度来看,404甚至不意味着资源不存在。这只意味着服务器没有所请求资源的当前可用表示,这甚至可能只是暂时的。因此,严格按照HTTP规范,404对于不存在所请求的东西本身是不可靠的。 如果您想要明确地表示所请求的东西不存在,则不要使用404

使用公共枚举对响应内容进行编码,以允许客户端打开它并相应地派生逻辑。我不知道你的客户如何区分“数据未找到”404和“网络资源未找到”404之间的区别?你不希望有人浏览到userZ/9,并让客户端怀疑是否请求是有效的,但没有返回数据。

为了总结或简化,

2xx:可选数据:格式良好的URI: Criteria不是URI的一部分:如果Criteria是可选的,可以在@RequestBody和@RequestParam中指定,应该导致2xx。例如:按名称/状态过滤

标准是URI的一部分:如果标准是强制性的,只能在@PathVariable中指定,那么它应该导致4xx。例如:按唯一id查找。

对于要求的情况: "users/9"将是4xx(可能是404) 但是对于“用户”呢?Name =superman"应该是2xx(可能是204)

为什么不用410呢?它表明所请求的资源不再存在,并且客户端希望永远不会对该资源发出请求,在您的例子中是users/9

你可以在这里找到关于410的更多细节:https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

根据w3的帖子,

200好了

请求成功。随响应返回的信息取决于请求中使用的方法

202年接受

请求已接受处理,但处理尚未完成。

204无内容

服务器已经完成了请求,但不需要返回实体主体,并且可能希望返回更新后的元信息。

400错误请求

由于语法错误,服务器无法理解请求。客户不应该在没有修改的情况下重复请求

401年未经授权

请求需要用户身份验证。响应必须包含一个WWW-Authenticate报头字段

404未找到

服务器没有发现任何与Request-URI匹配的内容。没有说明这种情况是暂时的还是永久的

这里有两个问题。一个在标题中,一个在例子中。我认为,这在一定程度上导致了关于哪种反应是合适的争议。

问题标题询问空数据。空数据仍然是数据,但不等于没有数据。因此,这意味着请求一个结果集,即一个列表,可能来自/users。如果一个列表是空的,它仍然是一个列表,因此204(无内容)是最合适的。您刚刚请求了一个用户列表,并得到了一个列表,它只是碰巧没有内容。

相反,所提供的示例询问一个特定的对象,即用户/users/9。如果没有找到用户#9,则不返回任何用户对象。您请求一个特定的资源(一个用户对象),但由于没有找到而没有得到它,因此404是合适的。

我认为解决这个问题的方法是,如果您可以在不添加任何条件语句的情况下使用响应,那么使用204,否则使用404。

在我的例子中,我可以迭代一个空列表而不检查它是否有内容,但是我不能在一个空对象上显示用户对象数据而不破坏一些东西或添加一个检查来查看它是否为空。

当然,如果适合您的需要,您可以使用空对象模式返回一个对象,但这是另一个线程的讨论。

204号更合适。特别是当你有一个警报系统来确保你的网站是安全的,404在这种情况下会引起混乱,因为你不知道一些404警报是后端错误或正常的请求,但响应为空。

起初,我认为204是有意义的,但经过讨论,我相信404是唯一真正正确的回答。考虑以下数据:

用户:约翰,彼得

METHOD  URL                      STATUS  RESPONSE
GET     /users                   200     [John, Peter]
GET     /users/john              200     John
GET     /unknown-url-egaer       404     Not Found
GET     /users/kyle              404     User Not found
GET     /users?name=kyle`        200     []
DELETE  /users/john              204     No Content

背景知识:

  1. 搜索返回一个数组,它只是没有任何匹配,但是 它的内容是:空数组.

  2. 404当然是最著名的url不支持 请求的服务器,但缺少资源实际上是相同的。
    即使/users/:nameusers/kyle匹配,用户 凯尔没有可用资源,所以404仍然适用。它不是 搜索查询,它是由动态url直接引用,所以它是404

  3. 根据评论中的建议,自定义404消息是另一种帮助API使用者更好地区分完全未知路由和缺失实体的方法。

不管怎样,我的意见。

我想说,这两个都不太合适。 正如@anneb所说的,我也认为部分问题来自于使用HTTP响应代码来传输与RESTful服务相关的状态。REST服务关于其自身处理的任何信息都应该通过特定于REST的代码来传输

1

我认为,如果HTTP服务器发现任何服务已经准备好响应它发送的请求,它不应该响应HTTP 404——最后,服务器找到了一些东西——除非处理请求的服务明确地告诉它。

让我们暂时假设以下URL: http://example.com/service/return/test

  • 情况A是服务器“只是在文件系统上查找文件”。如果它不存在,404是正确的。同样,如果它要求某种服务准确地交付该文件,而该服务告诉它没有此名称的文件存在,情况也是如此。
  • 在情况B中,服务器不处理“真正的”文件,而实际上请求是由其他服务处理的——例如某种模板系统。在这里,服务器不能声明资源的存在,因为它对资源一无所知(除非处理它的服务告诉它)。

如果没有来自服务的任何响应显式地要求不同的行为,HTTP服务器只能说3件事:

  • 503如果应该处理请求的服务没有运行或响应;
  • 200否则作为HTTP服务器实际上可以满足请求-不管服务稍后会说什么;
  • 400404表示没有这样的服务(相对于“存在但脱机”),并且没有找到其他服务。

2

回到手头的问题:我认为最干净的方法是不使用HTTP任何响应代码,除了前面说过的。如果服务存在并响应,HTTP代码应该是200。 响应应该在一个单独的报头中包含服务返回的状态-在这里,服务可以说

  • REST:EMPTY例如,如果它被要求搜索某物,该研究返回空;
  • REST:NOT FOUND,如果它被特别地请求某事物。“ID-like”-是一个文件名或一个ID的资源或条目号24等-并且那个特定的资源没有找到(通常,一个特定的资源被请求但没有找到);
  • REST:INVALID如果它发送的请求的任何部分不被服务识别。

(注意,我故意用“REST:”作为前缀,以标记这样一个事实,即虽然它们可能具有与HTTP响应代码相同的值或措辞,但它们是完全不同的东西)

3.

让我们回到上面的URL,检查情况B,其中服务向HTTP服务器表明它不处理这个请求本身,而是将它传递给SERVICE。HTTP只提供SERVICE返回的内容,它不知道return/test部分的任何信息,因为它是由SERVICE处理的。如果该服务正在运行,HTTP应该返回200作为确实发现了什么来处理请求。

SERVICE返回的状态(如上所述,它希望在单独的头文件中看到)取决于实际期望的操作:

  • 如果return/test请求一个特定的资源:如果它存在,返回状态为REST:FOUND;如果该资源不存在,返回REST:NOT FOUND;如果我们知道它曾经存在并且不会返回,则可以扩展为返回REST:GONE,如果我们知道它已经去了好莱坞,则可以扩展为返回REST:MOVED
  • 如果return/test被认为是一个搜索或类似过滤器的操作:如果结果集是空的,返回一个请求类型的空集和REST:EMPTY的状态;请求类型的一组结果和REST:SUCCESS的状态
  • 如果return/test不是SERVICE能识别的操作:如果它完全错误(例如retrun/test这样的错别字),则返回REST:ERROR,如果计划稍后执行则返回REST:NOT IMPLEMENTED

4

这种区别比把两种不同的东西混在一起要清楚得多。它还将使调试更容易,处理也只是稍微复杂一些。

  • 如果返回一个HTTP 404,服务器会告诉我,“我不知道你在说什么”。虽然请求的REST部分可能完全没问题,但我在所有错误的地方都在寻找par'Mach。
  • 另一方面,HTTP 200和REST:ERR告诉我,我得到了服务,但在对服务的请求中做了错误的事情。
  • 从HTTP 200和REST:EMPTY,我知道我没有做错什么-正确的服务器,服务器找到了服务,正确的请求到服务-但搜索结果是空的。

总结

这个问题和讨论源于这样一个事实:HTTP响应码被用来表示一个服务的状态,而这个服务的结果是由HTTP提供的,或者用来表示不在HTTP服务器本身范围内的某个事物。 由于这种差异,这个问题无法回答,所有的意见都要经过大量的讨论

由服务而不是HTTP服务器处理的请求的状态真的不应该(RFC 6919)由HTTP响应代码给出。HTTP代码应该(RFC 2119)只包含HTTP服务器从自己的作用域提供的信息:即,是否发现服务在处理请求。

相反,应该使用一种不同的方式将请求的状态告知使用者,以告知实际处理请求的服务。我的建议是通过一个特定的头文件来实现。理想情况下,报头的名称及其内容都遵循一种标准,使使用者可以很容易地处理这些响应。

现有的答案没有详细说明使用路径参数还是查询参数是有区别的。

  • 对于路径参数,参数是资源路径的一部分。在/users/9的情况下,响应应该是404,因为没有找到该资源。/users/9是资源,结果是一元的,或者是一个错误,它不存在。这是一个单子。
  • 对于查询参数,参数不是资源路径的一部分。在/users?id=9的情况下,响应应该是204,因为找到了资源/users,但它不能返回任何数据。资源/users存在且结果为n-ary,即使它为空也存在。如果id是唯一的,这个是一个单子。

使用路径参数还是查询参数取决于用例。我更喜欢将路径参数用于强制的、规范的或标识参数,将查询参数用于可选的、非规范的或属性参数(如分页、排序区域设置等)。在REST API中,我将使用/users/9而不是/users?id=9,特别是因为可能嵌套来获取“子记录”,例如/users/9/ssh-keys/0获取第一个公共ssh密钥或/users/9/address/2获取第三个邮政地址。

我更喜欢使用404。原因如下:

  • 对一元(1个结果)和n元(n个结果)方法的调用不应该无缘无故地变化。如果可能的话,我希望有相同的响应代码。预期结果的数量当然是不同的,例如,您期望主体是一个对象(一元)或一个对象数组(n元)。
  • 对于n-ary,我会返回一个数组,如果没有结果,我不会返回任何集合(没有文档),我会返回一个空集合(空文档,就像JSON中的空数组或XML中的空元素)。也就是说,它仍然是200,但是没有记录。除了在主体中之外,没有理由将此信息放在导线中。
  • 204类似于void方法。我不会将它用于GET,只用于POSTPUTDELETE。我在GET的情况下做了一个例外,其中标识符是查询参数而不是路径参数。
  • 找不到记录就像NoSuchElementExceptionArrayIndexOutOfBoundsException或类似的东西,由客户端使用不存在的id引起,所以,这是客户端错误。
  • 从代码的角度来看,获得204意味着代码中可以避免的额外分支。它使客户端代码变得复杂,在某些情况下,它也使服务器代码变得复杂(取决于你是使用实体/模型单子还是普通实体/模型;我强烈建议远离实体/模型单子,这可能会导致严重的错误,因为单子你认为一个操作是成功的,当你实际上应该返回其他东西的时候返回200或204)。
  • 如果2xx表示服务器做了客户端请求的事情,而4xx表示服务器没有做客户端请求的事情,这是客户端的错,那么客户端代码就更容易编写和理解。没有给客户端id请求的记录是客户端的错误,因为客户端请求的id不存在。

最后一点:一致性

  • GET /users/9
  • PUT /users/9DELETE /users/9

如果成功更新或删除,PUT /users/9DELETE /users/9已经必须返回204。如果用户9不存在,它们应该返回什么?根据所使用的HTTP方法将相同的情况显示为不同的状态代码是没有意义的。

此外,这不是一个规范的原因,而是一个文化原因:如果204用于GET /users/9,那么在项目中会发生的下一件事是,有人认为返回204对n-ary方法有好处。这使客户端代码变得复杂,因为客户端现在必须专门检查204,在这种情况下跳过解码正文,而不是仅仅检查2xx然后解码正文。但是客户会怎么做呢?创建空数组?那为什么不在电话里录下来呢?如果客户端创建空数组,204是一种愚蠢的压缩形式。如果客户端使用null代替,则打开了一个完全不同的蠕虫罐头。

Twitter使用404,并带有类似“找不到数据”的自定义错误消息。

裁判:https://developer.twitter.com/en/docs/basics/response-codes.html

根据RFC7231 - page59(https://www.rfc-editor.org/rfc/rfc7231#page-59) 404状态码响应的定义是:

< p > < em > 6.5.4。404未找到 404(未找到)状态代码表示源服务器找到了 没有找到目标资源的当前表示形式,或者没有 愿意透露一个存在。404状态代码则不然 说明这种缺乏代表是暂时的还是 永久性的;状态码410 (Gone)优于404 源服务器大概通过一些可配置的方式知道这一点 这种情况很可能是永久性的。 默认情况下,404响应是可缓存的;也就是说,除非另有规定 由方法定义或显式缓存控件指示(请参阅

. [RFC7234]第4.2.2节) 而引起质疑的主要是上面上下文中对资源的定义。 根据同一个RFC(7231), resource的定义是:

< p > < em >资源: HTTP请求的目标被称为“资源”。HTTP没有 限制资源的性质;它仅仅定义了一个接口 可能用于与资源交互。每个资源都是 由统一资源标识符(URI)标识,如 [RFC7230]第2.7节。 当客户机构造HTTP/1.1请求消息时,它将发送 目标URI的一种形式,定义在(章节5.3) [RFC7230])。当接收到请求时,服务器重新构造一个 目标资源的有效请求URI(章节5.5) [RFC7230])。 HTTP的一个设计目标是将资源标识与 请求语义,通过授予请求而实现 请求方法中的语义(第4节)和一些 请求修改报头字段(章节5)。如果有冲突 方法语义和URI所暗示的任何语义之间 方法本身,如4.2.1节所述,方法语义采取 优先。< / em > < / p >

所以在我的理解中,404状态代码不应该用于成功的GET请求,结果为空。(例如:一个没有特定过滤器结果的列表)

在看完问题后,你不应该使用404为什么?

基于RFC 7231,正确的状态代码是204

在上面的回答中,我注意到一个小错误:

1.—资源为:/users

2.- /users/8不是资源,这是:资源/users路由参数8,消费者可能不会注意到它,不知道区别,但发布者知道,必须知道这一点!…所以他必须为消费者返回一个准确的响应。时期。

所以:

基于RFC: 404是不正确的,因为找到了资源/users,但是使用参数8执行的逻辑没有找到任何content作为响应返回,因此正确答案是:204

这里的要点是:404甚至没有找到资源来处理内部逻辑

204是a:我找到了资源,逻辑被执行了,但我没有发现任何数据使用你在路由参数中给出的标准,所以我不能返回任何东西给你。对不起,核实你的标准后再打电话给我。

200:好吧,我找到了资源,逻辑被执行(即使当我不被迫返回任何东西)采取这一点,并在你的意愿使用它。

205:(GET响应的最佳选项)我找到了资源,逻辑已经执行,我有一些内容给你,好好使用它,哦,顺便说一下,如果你要在一个视图中共享这个,请刷新视图以显示它。

希望能有所帮助。

这样的事情可能是主观的,双方都有一些有趣和各种扎实的论点。然而[在我看来]对于缺失的数据返回404是不正确的。这里有一个简单的描述来说明这一点:

  • 请求:能给我一些数据吗?
  • 资源(API端点):我将在这里为您获取请求[发送潜在数据的响应]

没有问题,找到了端点,找到了表和列,因此查询了DB,并“成功”返回了数据!

现在,无论“成功响应”是否有数据都不重要,您要求“潜在”数据的响应,并且具有“潜在”数据的响应得到了满足。Null,空等是有效的数据。

200只代表我们的请求成功了。我正在请求数据,HTTP/REST没有任何问题,作为数据(尽管为空)返回我的“数据请求”是成功的。

返回一个200,让请求者在每个特定场景下处理空数据!

想想这个例子:

  • 请求:查询用户ID为1234的“违规”表
  • 资源(API端点):返回一个响应,但数据为空

此数据为空是完全有效的。这意味着用户没有违规行为。这是200,因为它是有效的,然后我可以这样做:

你没有违规,吃个蓝莓松饼!

如果你认为这是404,你在说什么?无法发现用户的违规行为?从语法上讲,这是正确的,但在REST世界中,成功或失败是关于请求的,这是不正确的。该用户的“违规”数据可以成功找到,没有违规-一个实数代表有效状态。


(厚颜无耻的注意。)

在你的标题中,你下意识地认为200是正确的回答:

有效的请求但空数据的正确REST响应代码是什么?


在选择使用哪种状态码时,抛开主观性和棘手的选择,以下是一些需要考虑的事情:

  1. 一致性。如果使用404表示“无数据”,则使用每一次,响应将返回无数据。
  2. 同一个状态不要有多个意思。如果在没有找到资源时返回404(例如API端点不存在等),那么也会使用它来表示没有返回数据。这只会让应对反应变成一种痛苦。
  3. 仔细考虑上下文。什么是“请求”?你说你想达到什么目的?

如果仅仅因为没有响应数据而返回404,则任何客户端都会感到非常困惑。

对我来说,响应代码200和一个空的主体足以理解一切都是完美的,但没有数据匹配的要求。

根据Microsoft: 控制器动作返回类型在ASP。NET核心web API,向下滚动几乎到底部,你会发现以下关于404的简介与数据库中没有找到的对象有关。在这里,他们建议404适用于空数据。

enter image description here

令人难过的是,如此简单和明确的东西在这个帖子中变成了“基于意见的”。

HTTP服务器只知道“实体”,这是对任何内容的抽象,可以是静态网页、搜索结果列表、其他实体列表、某物的json描述、媒体文件等等。

每个这样的实体都应该由一个唯一的URL来识别,例如。

  • /user/9——一个单独的实体:user ID=9
  • /users——单个实体:所有用户的LIST
  • /media/x.mp3——一个单独的实体:一个名为x.mp3的媒体文件
  • /search—单个实体:基于查询参数的动态CONTENT

如果一个服务器通过给定的URL找到一个资源,它的内容是什么并不重要——2G的data, null,{},[]——只要它存在,它就会是200。但是如果服务器不知道这个实体,它将返回404“not Found”。

一个困惑似乎来自开发人员,他们认为如果应用程序具有特定路径形状的处理程序,那么它就不应该是错误。从HTTP协议的角度来看,服务器内部发生了什么并不重要。无论默认路由器响应还是特定路径形状的处理程序),只要服务器上没有与所请求的URL(所请求的MP3文件,网页,用户对象等)匹配的实体,这将返回有效内容(空或其他),它必须是404(或410等)。

另一个令人困惑的地方似乎是“没有数据”和“没有实体”。前者是关于实体的内容,后者是关于实体的存在。

示例1:

  • No data: /users返回200 OK,正文:[],因为还没有人注册
  • 没有实体:/users返回404,因为没有路径/users

示例2:

  • No data: /user/9返回返回200 OK,正文:{},因为用户ID=9从未输入他/她的个人数据
  • 没有实体:/user/9返回404,因为没有用户ID=9

示例3:

  • No data: /search?name=Joe返回200 OK[],因为DB中没有Joe
  • 没有实体:/search?name=Joe返回404,因为没有路径/搜索

正如许多人所说的,404会误导客户端,如果请求uri不存在,或者请求的uri不能获取请求的资源,它不允许客户端进行区分。

200状态被期望包含资源数据-所以它不是正确的选择。 204状态意味着完全不同的东西,不应该被用作GET请求的响应

由于这样或那样的原因,所有其他现有状态都不适用。

我看到这个话题在很多地方被反复讨论。对我来说,很明显,要消除围绕这个话题的困惑,就需要一个专门的成功状态。类似于“209 -没有资源显示”。

这将是一个2xx状态,因为找不到ID不应该被认为是客户端错误(如果客户端知道服务器DB中的所有内容,它们就不需要向服务器询问任何事情,不是吗?)这个专用状态将解决所有与使用其他状态争论的问题。

唯一的问题是:我如何让RFC接受这个标准?

在这个场景中,Ruby on Rails响应404 Not Found

客户端请求不存在的资源。因此,404 Not Found更合适。


编辑

我发现,在这种情况下,许多开发人员不喜欢404 not found

如果你不想使用404,我认为,你可以使用这两个响应代码中的任何一个:

  • 200好了
  • 204无内容

如果你使用200 OK:响应体应为empty json:[]{}

如果你使用204 OK:响应体应为空。

只是一个开发者在这种情况下挣扎了很多次的附加内容。您可能已经注意到,当特定资源不存在时,总是会讨论是否返回404、200或204。上面的讨论表明,这个主题非常令人困惑,而且是基于意见的(尽管存在http-status-code标准)。 我个人建议,正如我还没有提到的,无论你如何决定在你的api定义中记录it。当然,当客户端开发人员使用你的“Rest”- api来使用他/她的Rest知识时,他/她会想到你的api是这样工作的。我猜你看到陷阱了。因此,我使用自述文件,其中明确定义了在哪些情况下使用哪种状态代码。这并不意味着我使用了一些随机的定义。我总是尝试使用标准,但为了避免这种情况,我记录了我的使用情况。客户可能会认为你在某些特定情况下是错误的,但因为它是有文档记录的,所以没有必要讨论如何节省你和开发人员的时间

Ops问题的一句话:当我回想开始开发后端应用程序时,我在Controller -route中配置了错误的东西,因此我的Controller方法没有被调用,404是一个总是出现在我脑海中的代码。考虑到这一点,我认为如果请求确实在Controller方法中到达了您的代码,则客户端执行了一个有效的请求,并且找到了请求端点。因此,这是一个不要使用404的指示。如果db查询返回未找到,则返回200,但主体为空。

TL;博士:

  • 如果在/users/9上没有找到用户,则应该返回404。
  • 如果在/users?id=9处没有找到用户,则应该返回204。

长版:

在回顾了我自己对这些状态代码的使用和本文中的示例之后,我不得不说,如果在/users/9的url中没有找到用户#9,404是适当的响应。

今天在我的系统中,我们的Application Insights日志中充满了数百个记录的404错误,这些错误使我们的日志变得混乱,这都是因为我们决定在/users/9没有相关数据时返回404。然而,这并不意味着我们在设置反应时的方法不正确,相反,我认为这意味着我们在设置路由时的方法不正确。

如果您希望端点获得大量流量,并且担心记录太多404错误,那么您应该更改路由以符合您想要的状态码,而不是强制使用不适当的状态码。

我们已经决定对我们的代码做2个更改:

  1. 通过期待/users?id=9来改变我们的工作路线
  2. 将我们的错误代码更改为204,这样404就不会填满我们的AI日志。

最后,API的架构师需要了解他们的API将如何被使用,以及哪种路由将适合于该用例。

我相信在/users/9的情况下,你请求的资源是用户本身,用户#9;您正在请求服务器响应一个标识为“9”的对象;它恰好存在于一个含有“user”的路径中。如果没有找到该对象,则应该得到404。

然而,如果你调用/users?id=9,我觉得你请求的资源是用户控制器,同时也提供了更多的专一性,这样它就不会返回所有用户的完整列表。您要求服务器响应一个可以通过查询字符串中定义的ID号识别的特定用户。因此,如果没有找到数据,204对我来说是有意义的,因为即使没有找到数据,控制器也是。

查询字符串方法还完成了一些我认为不仅有助于API开发人员,而且有助于客户端开发人员(特别是初级开发人员或继承这段代码或调用它的代码的未来开发人员):

任何人都清楚9是一个标识,而不是任意的数字。在这样一个基本的示例中,这一点似乎没有意义,但是请考虑使用guid作为行ID的系统,或者允许您通过人名获取数据的系统,或者甚至是返回特定ZIP/邮政编码信息而不是行ID的系统。如果他们一眼就知道标识参数是姓、名、全名还是ZIP/邮政编码,而不是ID,这对所有相关的开发人员都很有用。

我不认为404是正确的回应。

如果使用404,如何知道是没有找到api,还是数据库中的记录没有找到?

从你的描述,我会使用200 OK,因为你的api执行所有逻辑没有任何问题。只是在数据库中找不到记录。所以,这不是API问题,也不是数据库问题,这是你的问题,你认为记录存在,但它不存在。因此,API执行成功,数据库查询执行成功,但没有发现任何返回。

因此,在这种情况下,我会用

200好了

使用空响应,如数组的[]或对象的{}。

根据w3,我相信以下几点:

2 xx:

这类状态代码表示成功接收、理解并接受了客户机的请求。

4 xx:

4xx类状态代码用于客户端似乎出现错误的情况。

如果客户端请求/users,并且它有用户列表,响应代码将是200 OK(客户端请求是有效的)。

如果客户端请求/users并且没有数据,则响应代码仍然是200 OK
被请求的实体/资源是用户列表,列表存在,只是其中没有任何用户(如果给出空响应,可以使用204 No Content,尽管我认为空列表[]会更好)。
客户端请求是有效的,资源确实存在,所以4xx响应代码在这里没有意义

另一方面,如果客户端请求/users/9,而该用户不存在,则客户端错误地请求了一个不存在的资源,即用户。在这种情况下,用404 Not Found来回答是有意义的。

这个话题中的答案(在撰写本文时已经有26个)完美地说明了开发人员理解他们正在使用的构造的语义是多么重要。

如果不理解这一点,那么响应状态代码是响应的属性而不是其他属性就不明显了。这些代码存在于响应的上下文中,它们在此上下文中之外的含义是未定义的。

响应本身就是请求的结果。请求对资源进行操作。资源、请求、响应和状态代码是HTTP的结构,就HTTP而言:

HTTP提供了与资源交互的统一接口(第2节),无论其类型、性质或实现如何,通过操作和传输表示(第3节)。

换句话说,响应状态码的范围受到一个接口的限制,该接口只关心一些目标资源,并处理用于与这些资源交互的消息。服务器应用程序逻辑超出了范围,您使用的数据也不重要。

当使用HTTP时,它总是与资源一起使用。资源被以太转移或操纵。在任何情况下,除非我们在量子世界中,资源要么存在要么不存在,不存在第三种状态。

如果发出HTTP请求来获取(传输)资源的表示(如本问题中所示),而资源不存在,则响应结果应该显示一个带有相应404代码的失败。目标-获取表示-没有达到,资源没有找到。在HTTP上下文中不应该有对结果的其他解释。

RFC 7231超文本传输协议(HTTP/1.1):语义和内容,在这里被多次引用,但主要是作为状态码描述的参考。我强烈建议通读整个文档,而不仅仅是第6节,以便更好地理解HTTP接口及其组件的作用域和语义。

我们现在看到的是两种范式之间的紧张关系。

在HTTP和REST中,URL标识一个资源,即user/9资源包括9。因此HTTP应该返回404—未找到。这就是RESTful的定义。之后,你可以PUT user/9,然后当你得到然后下一次,你得到数据。这就是HTTP和REST的设计方式。

在HTTP级别,如果你不想要404,一个更好的URL应该是user?id=9,然后user部分会被找到,函数可以做它自己的处理,并返回它自己的方式通知“未找到”。

然而,为了方便指定api,它只是“好得多”;使用user/9格式。这给我们留下了一个困境:这个请求是通过HTTP发出的,(固执的)正确的HTTP答案是404;但是从API消费者的角度来看,框架可能不能很好地处理404,他们想要一个200 +的“not found”;有效负载(204对很多框架来说也是个问题)。

这种将API放在已经定义的协议(HTTP)之上的做法导致了这种紧张。当设计成一个真正的RESTful API时(并且正确地处理404错误),这是没有问题的。

如果你认为user/9应该返回200 +“not found”,那么你使用user作为RPC端点,然后在URL的其余部分编码参数。我认为这是一种糟糕的设计,与RESTful规范相反,并且完全理解我们是如何走到这一步的。

如果你控制了两端,考虑到你的服务器和客户端框架的限制,就做那些有效的事情。

(想想在user/9上执行HEAD请求的后果——你不能在响应中提供任何内容。200表示user/9确实存在,而404(正确地)表示它不存在。)