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

问题描述 投票:245回答:15

例如,您为users/9运行GET请求,但没有id为#9的用户。哪个是最好的响应代码?

  • 200好的
  • 202接受
  • 204没有内容
  • 400错误请求
  • 404未找到
rest http api-design
15个回答
203
投票

TL; DR:使用404

This Blog。它解释得非常好。

关于204的博客评论摘要:

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

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

其他响应代码甚至不如204404

  1. 200应该与你成功取得的任何身体一起归还。当您提取的实体不存在时不合适。
  2. 当服务器开始处理某个对象但该对象尚未完全准备好时,将使用202。当然不是这里的情况。您尚未开始,也不会开始构建用户9以响应GET请求。这破坏了各种规则。
  3. 400用于响应格式不正确的HTTP请求(例如格式错误的http标头,错误排序的段等)。这几乎肯定会由你正在使用的任何框架来处理。除非您从头开始编写自己的服务器,否则不必处理此问题。编辑:Newer RFCs现在允许400用于语义无效的请求。

维基百科的description of the HTTP status codes特别有用。您还可以看到in the HTTP/1.1 RFC2616 document at www.w3.org的定义


3
投票

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


3
投票

Twitter使用404与自定义错误消息,如“找不到数据”。

参考:https://developer.twitter.com/en/docs/basics/response-codes.html


2
投票

我会说,两者都不合适。如前所述 - 例如通过@anneb,我也认为部分问题源于使用HTTP响应代码来传输与RESTful服务相关的状态。 REST服务必须通过REST特定代码传输有关其自身处理的任何内容。

1

我认为,如果HTTP服务器发现任何准备好回答它被发送的请求的服务,它就不应该响应HTTP 404 - 最后,服务器找到了什么 - 除非明确说明处理请求的服务。

我们暂时假设以下网址: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” - 是ID或条目号24等的文件名或资源 - 并且未找到该特定资源(通常,请求并找不到一个特定资源);
  • REST:INVALID,如果发送请求的任何部分未被服务人员识别。

(请注意,为了标记这些事实,虽然这些可能与HTTP响应代码具有相同的值或措辞,但它们与“REST:”前缀这些事实,它们是完全不同的)

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的状态
  • 如果qazxsw poi不是qazxsw poi认可的操作:返回return/test,如果它是完全错误的(例如像SERVICE这样的错字),或REST:ERROR以防万一计划以后。

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服务器可以从其自己的范围提供的信息:即,是否发现服务处理请求。

相反,应该使用不同的方式告诉消费者有关实际处理请求的服务的请求的状态。我的建议是通过特定标题这样做。理想情况下,标题的名称及其内容都遵循一个标准,使消费者可以轻松地使用这些响应。


2
投票

根据RFC7231 - page59(retrun/test)404状态代码响应的定义是:

6.5.4。 404未找到404(未找到)状态代码表示源服务器未找到目标资源的当前表示,或者不愿意透露存在该目标资源。 404状态代码并不表示这种缺乏代表性是暂时的还是永久性的;如果原始服务器通过某些可配置方式知道该条件可能是永久性的,则410(Gone)状态代码优先于404。默认情况下,404响应可缓存;即,除非方法定义或显式高速缓存控制另有说明(参见[RFC7234]的第4.2.2节)。

带来疑虑的主要因素是上述背景下的资源定义。根据相同的RFC(7231),资源的定义是:

资源:HTTP请求的目标称为“资源”。 HTTP不限制资源的性质;它只定义了一个可能用于与资源交互的接口。每个资源由统一资源标识符(URI)标识,如[RFC7230]第2.7节中所述。当客户端构造HTTP / 1.1请求消息时,它以各种形式之一发送目标URI,如[RFC7230]第5.3节中所定义。收到请求后,服务器会重建目标资源的有效请求URI([RFC7230]的第5.5节)。 HTTP的一个设计目标是将资源标识与请求语义分开,这可以通过将请求语义归入请求方法(第4节)和一些请求修改标头字段(第5节)来实现。如果方法语义与URI本身隐含的任何语义之间存在冲突,如第4.2.1节所述,则方法语义优先。

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


2
投票

在查看问题后,你不应该使用REST:NOT IMPLEMENTED为什么?

基于https://tools.ietf.org/html/rfc7231#page-59,正确的状态码是404

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

1.-资源是:RFC 7231

2.- 204不是资源,这是:资源/users与路由参数/users/8,消费者可能无法注意到它并且不知道差异,但发布者确实并且必须知道这个!...所以他必须返回准确的响应对消费者而言期。

所以:

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

这里的要点是:content甚至没有发现资源处理内部逻辑

204是一个:我找到了资源,逻辑被执行但是我没有找到任何数据使用你在route参数中给出的标准,所以我不能给你任何东西。对不起,请验证您的标准并再次给我打电话。

404:好的,我找到了资源,逻辑被执行了(即使我没有被迫返回任何东西)拿走它并按照你的意愿使用它。

204 :( GET响应的最佳选择)我找到了资源,逻辑被执行了,我有一些内容给你,使用得很好哦,顺便说一句如果你要在视图中分享这个请刷新视图显示它。

希望能帮助到你。


1
投票

为什么不使用410?它表明请求的资源不再存在,并且客户端永远不会请求该资源,在您的情况下200

你可以在这里找到有关410的更多细节:205


0
投票

使用通用枚举对响应内容进行编码,允许客户端切换它并相应地分叉逻辑。我不确定您的客户如何区分“未找到数据”404和“未找到网络资源”404之间的区别?你不希望有人浏览到userZ / 9并让客户端惊讶,好像请求有效但没有返回数据。


275
投票

我强烈反对404赞成204或200空数据。

收到并正确处理了请求 - 它确实触发了服务器上的应用程序代码,因此无法确定它是客户端错误,因此整个客户端错误代码类(4xx)不合适。

更重要的是,404可能由于多种技术原因而发生。例如。应用程序暂时停用或卸载在服务器上,代理连接问题和诸如此类的东西。因此,客户端无法区分表示“空结果集”的404和表示“无法找到服务的404,稍后再试”。

这可能是致命的:想象一下您公司的会计服务,其中列出了年度奖金所需的所有员工。不幸的是,有一次它被调用它返回404.这是否意味着没有人应该获得奖金,或者应用程序当前是否因新部署而停止?

- >对于关心数据质量的应用程序,404因此几乎是不行的。

此外,许多客户端框架通过抛出异常而没有进一步的问题来响应404。这会强制客户端开发人员捕获该异常,对其进行评估,然后根据是否将其记录为由例如监控组件或是否忽略它。这对我来说似乎也不太好看。

404超过204的唯一优势是它可以返回一个响应实体,该实体可能包含有关未找到所请求资源的原因的一些信息。但如果这确实相关,那么人们也可以考虑使用200 OK响应并以允许有效载荷数据中的错误响应的方式设计系统。或者,可以使用404响应的有效载荷将结构化信息返回给调用者。如果他收到例如一个html页面,而不是他可以解析的XML或JSON,那么这是一个很好的指示,表明技术出现了问题,而不是从调用者的角度来看可能有效的“无结果”回复。或者可以使用HTTP响应头。

尽管如此,我仍然希望204或200有空响应。这样,请求的技术执行状态与请求的逻辑结果分开。 2xx表示“技术执行正常,这是结果,处理它”。

我认为在大多数情况下,应由客户决定是否可以接受空结果。尽管技术执行正确,但通过返回404,客户端可能会决定将案例视为错误而不是错误。

另一个快速类比:如果SQL查询没有返回任何结果,则返回404表示“找不到结果”就像抛出DatabaseConnectionException。它可以完成工作,但是有很多可能的技术原因引发相同的异常,然后将其误认为是有效的结果。


28
投票

起初,我认为204会有意义,但在讨论之后,我相信404是唯一真正正确的回应。请考虑以下数据:

用户:约翰,彼得

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

一些背景:

  1. 搜索返回一个数组,它只是没有任何匹配但它有内容:一个空数组。
  2. 404当然最为人所知的是所请求服务器不支持的url,但缺少的资源实际上是相同的。 即使/users/:nameusers/kyle匹配,用户Kyle也不是可用资源,因此仍然适用404。它不是搜索查询,它是动态网址的直接引用,因此404就是。

无论如何,我的两分钱:)


21
投票

如果预期资源存在,但它可能是空的,我会争辩说,通过表示该事物为空的表示可能更容易获得200 OK。

所以我宁愿/东西返回200 OK,{“Items”:[]}而不是204,什么都没有,因为这样一个带有0个项目的集合可以被视为与一个集合或者一个集合相同更多项目。

我只是为PUT和DELETE留下204 No Content,在那里可能没有实用的表示。

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


19
投票

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

对于对象存在,但没有数据,204 No Content是合适的。我认为在你的情况下,该对象不存在。


12
投票

根据w3帖子,

200好的

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

202接受

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

204没有内容

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

400错误请求

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

401未经授权

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

404未找到

服务器未找到与Request-URI匹配的任何内容。没有说明该病症是暂时的还是永久性的


9
投票

总结或简化,

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

4xx:预期数据:格式不正确URI:条件是URI的一部分:如果条件是强制性的,只能在@PathVariable中指定,那么它应该导致4xx。示例:按唯一ID查找。

因此对于问题情况:“users / 9”将是4xx(可能是404)但是对于“users?name = superman”应该是2xx(可能是204)


9
投票

有两个问题要问。一个在标题中,一个在示例中。我认为这部分导致了对哪种回应适当的争议。

问题标题询问空数据。空数据仍然是数据,但与无数据不同。因此,这表明请求结果集,即列表,可能来自/users。如果列表为空,则它仍然是列表,因此204(无内容)是最合适的。您刚刚要求提供一个用户列表并且已经提供了一个用户列表,它恰好没有内容。

提供的示例代之以询问特定对象,用户/users/9。如果未找到用户#9,则不返回用户对象。您询问了一个特定的资源(用户对象)并没有找到它,因为找不到它,所以404是合适的。

我认为解决这个问题的方法是,如果您可以按照预期的方式使用响应而不添加任何条件语句,那么使用204,否则使用404。

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

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


5
投票

现有的答案没有详细说明,无论您使用路径参数还是查询参数,它都会有所不同。

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

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

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

  • 对一元(1个结果)和n元(n个结果)方法的调用不应该因为没有充分的理由而变化。如果可能的话,我希望有相同的响应代码。预期结果的数量当然是有区别的,比如说,您希望身体是一个对象(一元)或一个对象数组(n-ary)。
  • 对于n-ary,我会返回一个数组,如果没有结果,我就不会返回任何set(没有文档),我会返回一个空集(空文档,如JSON中的空数组或XML中的空元素) )。也就是说,它仍然是200但没有记录。没有理由将这些信息放在身体以外的电线上。
  • 204就像一个void方法。我不会将它用于GET,仅用于POSTPUTDELETE。我在GET的情况下例外,其中标识符是查询参数而不是路径参数。
  • 没有找到记录就像NoSuchElementExceptionArrayIndexOutOfBoundsException或类似的东西,由客户端使用不存在的id导致,因此,这是一个客户端错误。
  • 从代码的角度来看,获取204意味着代码中可以避免的附加分支。它使客户端代码变得复杂,并且在某些情况下它也使服务器代码复杂化(取决于您使用实体/模型monad还是普通实体/模型;我强烈建议远离实体/模型monad,它可能导致令人讨厌的错误,因为你认为一个操作是成功的monad,当你实际上应该返回别的东西时返回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方法是有益的。这使客户端代码变得复杂,因为客户端现在必须专门检查2xx而不是仅检查204然后解码主体,并且在这种情况下跳过解码主体。芽取决于客户做什么?创建一个空数组?那为什么不在电线上呢?如果客户端创建空数组,则204是一种愚蠢的压缩形式。如果客户端使用null,则会打开一整套不同的蠕虫。

© www.soinside.com 2019 - 2024. All rights reserved.