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

IMB*_*IMB 289 rest api-design http

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

  • 200好的
  • 202接受
  • 204没有内容
  • 400错误请求
  • 404未找到

Jen*_*urm 306

我强烈反对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.它可以完成工作,但是有很多可能的技术原因引发相同的异常,然后将其误认为是有效的结果.

  • 提问者还询问了一个特定的资源:单个用户(不是`/ users`路由,但是`/ users/9`,即"用户称为#9"),所以你的'空结果集'比较没有没有意义.404表示该对象不存在. (38认同)
  • **'未找到'的技术**原因也称为服务器错误.这些应该在500年代.具体来说:"无法找到服务"是"503服务不可用". (26认同)
  • 404仅表示未找到所请求的**资源**(在这种情况下是用户编号9).它与应用程序代码是否被触发无关,它与后端应用程序是否响应无关.Web服务器就是问题所在,在问题中没有提到反向代理. (25认同)
  • 这个答案的推理是非常错误的. (25认同)
  • 404:客户端能够与给定服务器通信,但服务器无法找到所请求的内容.字面意思是:请求收到,它很好并且格式正确(错误请求400),它被认证或公开(未经授权401 /禁止403),无需支付(付款需要402),请求方法很好(方法不允许405) ),可以满足请求接受(不可接受406).当用户获取资源时,应该使用200 Ok.空不是资源.400范围用于客户端错误500范围用于服务器错误简而言之:您的推理已关闭. (19认同)
  • 是的,但是没有找到所请求资源的原因通常是从操作角度来看.是不是因为它不存在而被发现,或是因为该服务暂时不可用而未被发现?一个乏味的404隐藏了这个原因,并且许多客户端框架非常不合理地处理它,因为4xx被定义为错误响应代码.如果没有资源不是错误但是有效的情况,那么我认为2xx会更合适. (6认同)
  • 好吧,我两年来一直试图理解这个答案背后的原因,因为我认为这是明显的错误,但至少有58个人不同意我的看法.我认为我同意*search*类型端点的答案,但*不是*用于搜索单个记录的端点.甚至你的例子都表明这正是你想象的.我认为/那就是你所得到的.你能为我澄清一下吗? (6认同)
  • @Crisfole这并不是真正面向REST apis的所有Web服务器如何处理它.许多Web服务器一直在为URL丢弃404,即使通常有后端应用程序响应该URL.从Web服务器的角度来看,这可能是合乎逻辑的,但这使得404对于"反向代理"的REST api来说非常不可靠. (5认同)
  • 小心解释原因? (5认同)
  • REST 资源与 HTTP 资源相同吗?作为现实世界的比较:如果我向图书馆发送一封信,索取一本特定的书籍,我会惊讶地收到一封“地址未知”的回信。图书馆不应该滥用蜗牛邮件协议来让我知道他们找不到这本书。相反,我希望收到一封回信(相当于 HTTP 状态 200),解释未找到这本书。REST 服务与 HTTP 服务不同。REST 服务使用 HTTP 服务。状态 404 意味着 HTTP 未找到,而不是 REST 未找到? (5认同)
  • “404”正确而“204”错误的另一个原因是:同一资源上不同 HTTP 方法的状态代码的一致性。如果用户存在并成功更新或删除,`PUT /users/9` 和`DELETE /users/9` 将已经返回`204`。如果用户不存在,那些应该返回什么?那么,如果用户不存在,为什么`GET /users/9` 应该返回`204`?没有意义。 (4认同)
  • 我很惊讶有这么多人愿意用找不到数据的应用程序来混淆服务器 HTTP 代码。需要记住的一些事情:对未找到数据和未找到 HTTP 资源使用 404 违反了单一职责规则。当我作为开发人员对 404 做出反应时,现在我需要将异常处理放入我的代码中。找不到数据并不是“异常” 假设我处理了异常。是因为网址错误还是因为找不到数据。这会导致大量额外的编码工作。 (4认同)
  • 如果应用程序未部署或停止,则503而不是404当然是该情况的另一种解决方案,但这不是可以在应用程序代码中设置的内容.相反,它是服务器行为的一个方面,对于开发人员来说可能是遥不可及的.如果有疑问,我会假设最坏的情况,如果应用程序不可用,服务器返回404. (3认同)
  • 只是评论你添加的例子是更好的例子,为什么它应该是*错误*代码而不是成功代码.404应该*从不*用于表示服务已关闭.您有503服务不可用或502 Bad Gateway这样做. (3认同)
  • 我完全同意这个答案.每次调用API都应该返回一个带有状态消息的对象,并避免使用HTTP状态代码作为响应.将它包装成JSON可以帮助您监视您的应用程序,在世界上没有直接连接到客户端的RESTful api这样的东西.它总是*在中间,协调器,发现服务,身份验证,授权等等...... (3认同)
  • @TomaszPluskiewicz 我将其解释为“您正在寻找一个有效的地方,但其中没有任何内容”我在一个有效的地方寻找的信息对于解释结果很重要。知道文件可以访问但为空与由于卷被卸载而根本无法从文件系统读取是不同的。简单的 404 不允许进行这种区分。 (3认同)
  • 这里有很多好的讨论!我可以看到为什么404适用于REST ...但是男人很难将条件语句添加到我正在处理的应用程序中的每个列表中,以便在没有找到结果时处理404.在我的情况下,接收一个空的实体列表并以与查找结果时相同的方式处理它会更容易.就像其他应用程序(如mysql)一样,如果没有找到结果,则返回空数据集而不是错误... (2认同)
  • 请求/ users/9与请求/favicon.ico不同的是什么方式?我怀疑你如何回答这个问题,决定你是否认为"这个答案是非常错误的".答:没有区别.如果/favicon.ico不存在,则返回404 not found,因此如果/ users/9不存在则返回相同的内容.另外:@Crisfole提到"添加一个除了找不到的原因短语"; 这有点重要,完全可以缓解这条路线的问题. (2认同)
  • @Chris我听到了你的意见,但使用错误的状态代码会让你的API消费者更难以调试他们的代码.看到404?你知道你要么指路,要么资源不存在.此外,您可以自动处理404案例:您是从Ajax请求获得404,重新路由还是显示您的404页面.结束.必须特别处理它是一件好事,因为它迫使你在代码中决定如何处理它.没有什么能阻止你看到404,创建一个空响应,然后渲染它. (2认同)
  • @anneb REST 和 HTTP 几乎是同义词。来自维基百科“Fielding 的论文解释了 REST 原则,这些原则被称为‘HTTP 对象模型’……并用于设计 HTTP 1.1 和统一资源标识符 (URI) 标准”。 (2认同)
  • 我强烈反对对此采取强硬立场...作为前端开发人员,我更喜欢处理空数组并在其中添加我的逻辑,而不是处理错误,但也了解 404 如何更有意义。只是我的 0 美分。 (2认同)
  • 我在我工作的公司遇到了一个有争议的情况。我们有一个网关 API 将我们的 Web 应用程序请求集中到微服务。有许多微服务和相当多的路线,其中之一。有一种情况是,负责其中一个微服务的团队将所有空响应从空数组和 204 代码更改为 404 代码。我们进行了认真的交谈,以获取常识。在我们的例子中,我们考虑到找不到路由时也可能返回 404 代码,因此我们决定返回 204 和空数组。 (2认同)
  • 我还没有看到很多来自运营 PoV 的评论。当您是开发人员、运营团队或“基础设施”团队时,您想知道某项服务“表现良好”。这里经常使用的指标是服务返回的“4xx”和“5xx”响应的数量。在那里,你无法区分“404-这里什么也没找到-一切照常”和“404-某事真的错了-永远不会工作”响应。因此,从可观察性的角度来看,我绝对支持*不*返回“404”。也许我们需要一个像 @umberto-bar 提议的 RFC:一个新的“2xx”状态代码正是为此? (2认同)
  • 我很惊讶有这么多人不理解 REST 原则,因此认为_当找不到资源时_返回 2xx 是可以的。 (2认同)
  • @SørenBoisen 为什么“无内容”并不表示资源不存在? (2认同)
  • @VishalShah 例如,如果在应用程序停止时请求的上下文路径当前未知,则将部署 Web 应用程序的 tomcat 将响应 404。404 由中间件(例如配置错误的代理或 servlet 容器或应用程序服务器)“注入”,是我反对使用它们来传达资源真正不存在的主要论点之一。 (2认同)

Cri*_*ole 228

TL; DR:使用 404

请参阅此博客.它解释得非常好.

博客评论摘要204:

  1. 204 No Content 作为浏览器的响应代码并不是非常有用(尽管根据HTTP规范,浏览器确实需要将其理解为"不要更改视图"响应代码).
  2. 204 No Content 但是,这可能要表示成功,而不必返回一些AJAX的Web服务是非常有用的.(特别是在喜欢DELETEPOST不需要反馈的情况下).

因此,您的问题的答案就是404在您的案例中使用.204是一个专门的响应代码,您不应该经常返回到浏览器以响应GET.

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

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

维基百科对HTTP状态代码描述特别有用.您还可以在www.w3.org上的HTTP/1.1 RFC2616文档中查看定义

  • -1因为我强烈反对404作为对没有记录返回的*成功*调用的响应.作为一个处理非Web应用程序API的开发人员,我浪费了几个小时联系API的开发人员来追踪我调用的API端点为什么不存在,实际上它确实存在,它只是没有要报告的数据.关于204对浏览器不是特别有用,这有点像摇尾巴,因为在我们的智能设备领域中大多数API端点的使用不是基于浏览器的,而是那些可能使用AJAX的.很抱歉拿走积分. (190认同)
  • @MatthewPatrickCashatt你可以随心所欲地向下投票.我现在终于明白了*为什么*人们对我不屑一顾,但理由仍然是错误的.当收到404时,并不意味着该路由没有意义,这意味着该位置没有资源.完全停止.如果您在这样的用户不存在时请求`/ badurl`或`/ user/9`,则为真.开发人员可以通过添加比"未找到"更好的原因短语来提供帮助,但不是必需的. (33认同)
  • @Crisfole我倾向于不同意(尽管不是downvote,继续阅读),基于[W3定义404](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html),具体而言`服务器没有找到与Request-URI匹配的任何内容.Web /应用程序服务器实际上找到了与Request-URI匹配的ACTION,尽管db服务器没有.但是,它还说"这个状态代码通常在没有其他响应适用的时候使用",所以我认为在某种程度上验证了它的使用(即使我不同意/喜欢它). (16认同)
  • 注意:200s中的响应代码表示成功.400s中的响应代码表示失败.摘要,第一点和第二点,是关于'204`响应代码(无内容). (8认同)
  • 我不认为你正在解决我正在提出的观点:404是危险的混乱.依赖于调用者检查原因短语或响应正文意味着您不信任状态代码,在这种情况下它不起作用. (6认同)
  • @Crisfole加上Matt的评论,这是一个[有趣的链接](http://softwareengineering.stackexchange.com/questions/203492/when-to-use-http-status-code-404-in-an-api) .引用:*4xx代码告诉UA它做错了什么,它构造的请求是不正确的,不应该再试一次,至少没有一些修改.*404错误也会触发Node的请求承诺中的捕获条件繁琐的事情. (4认同)
  • @Stanislasdrg是的,我认为UA*在请求不存在的资源时做错了.设计良好的API将具有目录端点,可用于提前验证它是否存在. (4认同)
  • Adrian Baker 和许多其他人在这里没有区分的是所请求的抽象实体是否存在(如果未找到,则在某些情况下为 404 - 或 410),以及该路由的应用程序处理程序是否存在,该处理程序将检查该实体的存在。您很困惑,因为“但是该路线很好,我遇到了处理程序,所以这意味着它不是错误”。但你应该意识到 404 不是一个技术错误,它是一个应用程序错误,向客户端说“我知道你的意思,但没有你所请求的那样的东西!” (4认同)
  • 此外,如果你要求一些不存在的东西,那么这个词的任何定义都不会*成功*. (3认同)
  • REST是关于*资源*而非行动.`GET/users/2`是对"用户二号"的请求.特别是对于'GET`请求,目标是*从不*执行*任何*副作用(除非它记录视图或类似). (3认同)
  • 我认为争论的根本原因是 REST 中的“资源”与框架中的“动作”之间的区别。在 REST 意义上,URL“/users/9”表示用户 #9 的详细信息,是与“/users/8”不同的特定资源。如果用户 #9 不存在,则该资源(又名 URL)不存在(因此,响应代码为 404)。如果您不知道用户 #9 是否存在,您不应该首先调用 `/users/9` (因此,客户端错误)。更好的方法是对“/users”资源进行过滤,例如“/users?id=9”,这可能会返回带有空数组的 HTTP 200。 (3认同)
  • 你们的 API 都不使用错误消息吗?我编写的每个 API 都有错误消息来解释问题。在 404 上,我们会说“不存在具有给定 ID 的用户”。简单明了地解决问题。开发人员不再对为什么会收到 404 感到困惑,因为任何有头脑的人都会检查错误消息的响应。 (2认同)
  • 可以说,该请求是针对“ /患者/过敏/ 56”的,这是对青霉素过敏的参考。考虑以下两种情况:(1)API的混合从`/耐心/过敏/ {id}`到`/耐心/过敏/ {id}`沟通不畅,或者(2)混合了DNS记录,并且api请求被路由到另一个非API HTTP服务器。在这两种情况下,将应用程序错误(“我无法识别该ID,但我已识别您的请求”)与较低级别的协议错误(“我无法识别该URL”)混为一个响应(404)都会很糟糕结果。 (2认同)
  • @Crisfole实际上,有时您想要呈现不同的内容:请求成功时,但请求失败时返回空响应VS。即“该患者没有过敏”与“糟糕!找不到该页面。” 因此,我认为AdrianBaker的观点是将协议和应用程序层的关注分开。 (2认同)
  • 404 实在是太模糊了,任何经常使用 API 休息响应的人都会告诉你这一点。什么是不存在的?用户?终点?服务器?表还是数据库?还有别的事吗?带有空数据的响应是完全有效的,数据已找到,它是空的 (2认同)

Jus*_*ijn 47

起初,我认为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
Run Code Online (Sandbox Code Playgroud)

一些背景:

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

  2. 404当然最为人所知的是所请求服务器不支持的url,但缺少的资源实际上是相同的.
    即使/users/:name与之匹配users/kyle,用户Kyle也不是可用资源,因此404仍然适用.它不是搜索查询,它是动态网址直接引用,因此404就是.

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

  • 为REST API抛弃这种风格.没有客户应该要求/ users/kyle,除非通过调用/ users或/ users告诉资源存在吗?name = kyle (7认同)
  • 这是我最认同的答案。我希望 API 如何工作的完美示例。@GaryBarker 的评论也很完美。当您通过 ID 查找某个不存在的内容时,这是一个错误。在拨打电话之前您应该知道 ID 存在。主要是因为获得一些“成功”的空响应只会将错误进一步推进,可能会在执行 user.name 或其他操作时出现“无法读取未定义的属性名称”。 (4认同)
  • *这不是一个搜索查询,它是动态 URL 的直接引用,所以是 404。* 这个。 (3认同)
  • IMO 会产生 404,因为这是一个无效请求:Kyle 不存在,因此也不可能搜索他的朋友。 (2认同)
  • @JustusRomijn 我(当然)同意你的观点。我可能会再添加一行,我认为这是争论的关键:“GET /usrs/john 404 Not found”。开发人员无法区分错误路线和失踪人员。这就是为什么我提倡“GET /users/kyle 404 No such user”和“GET /usrs/john 404 Not found”。 (2认同)

j00*_*057 23

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

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

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

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

  • @The Muffin Man,我不知道你怎么能假装知道我更喜欢REST还是RPC,也不知道为什么它与关于返回HTTP GET请求的状态代码的讨论有关. (2认同)

Max*_*Max 20

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

对于对象存在,但没有数据,204 No Content是合适的.我觉得你的情况,对象也没有,虽然存在.


Jus*_*ode 13

根据w3帖子,

200好的

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

202接受

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

204没有内容

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

400错误请求

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

401未经授权

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

404未找到

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

  • w3 帖子是关于 HTTP 状态代码的。HTTP 与 REST 不同。REST 主要但不一定使用 HTTP 作为传输协议。404 是 HTTP 传输错误代码。如果 REST 与 HTTP 相同,它不应该称为 HTTP 吗? (2认同)

Dar*_*vic 11

令人遗憾的是,如此简单和明确定义的东西在此线程中变成了“基于意见”。

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

每个这样的实体都可以通过一个唯一的 URL 来识别,例如

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

如果一个服务器通过给定的 URL 找到一个资源,它的内容是什么都没有关系——2G 的数据,null,{},[]——只要它存在,它就是 200。但如果这样的实体是服务器不知道,预计返回 404“Not Found”。

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

另一个混淆点似乎是围绕“无数据”和“无实体”。前者是关于一个实体的内容,后者是关于它的存在。

示例 1:

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

示例 2:

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

示例 3:

  • 无数据:/search?name=Joe 返回 200 OK [],因为数据库中没有 Joe 的
  • 无实体:/search?name=Joe 返回 404,因为没有路径 /search


小智 10

总结或简化,

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

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

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


Blu*_*box 10

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

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

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

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

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

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


Chr*_*jer 6

现有答案未详细说明的是,无论您使用路径参数还是查询参数,都将有所作为。

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

使用路径参数还是查询参数取决于用例。我更喜欢使用路径参数作为强制性,规范性或标识性参数,而将查询参数作为可选性,非规范性或归属性参数(例如分页,整理语言环境和内容)。在REST API中,由于可能会嵌套以获取“子记录”(如获取第一个公共ssh密钥或获取第三个邮政地址),因此我/users/9/users?id=9特别使用。/users/9/ssh-keys/0/users/9/address/2

我更喜欢使用404。这是为什么:

  • 一元(1个结果)和n元(n个结果)方法的调用不应无缘无故变化。如果可能,我希望使用相同的响应代码。预期结果的数量当然是不同的,例如,您希望主体是一个对象(一元)或对象数组(n元)。
  • 对于n元,我将返回一个数组,如果没有结果,我将不返回没有集合(无文档),我将返回一个空集合(空文档,例如JSON中的空数组或XML中的空元素)。也就是说,它仍然是200,但记录为零。除了在身体上,没有其他理由将此信息放在电线上。
  • 204就像一种void方法。我不会用它GET,只为POSTPUTDELETEGET如果标识符是查询参数而不是路径参数,我会例外。
  • 没有找到记录是喜欢NoSuchElementExceptionArrayIndexOutOfBoundsException或者类似的东西,用一个id不存在,因此,它是一个客户端错误客户端造成的。
  • 从代码角度来看,获取204意味着可以避免在代码中增加分支。它会使客户端代码复杂化,并且在某些情况下还会使服务器代码复杂化(取决于您使用的是实体/模型单子还是普通的实体/模型;我强烈建议您远离实体/模型单子,这可能会导致令人讨厌的错误,因为表示您认为该操作成功了,并且当您实际上应该返回其他值时返回200或204)。
  • 客户端代码更容易编写和理解,如果2xx表示服务器执行了客户端请求的操作,而4xx表示服务器未执行客户端请求的操作,这是客户端的错误。没有向客户端提供该客户端请求的记录是客户端的错误,因为客户端请求的ID不存在。

最后但并非最不重要的一点:一致性

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

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

此外,不是规范性的,而是一种文化原因:如果204将其用于GET /users/9项目中将要发生的下一件事是有人认为返回204对n元方法有益。这使客户端代码变得复杂,因为2xx客户端现在不仅要检查并解码主体,还必须专门检查204并在这种情况下跳过对主体的解码。芽客户该怎么办?创建一个空数组?那为什么不把它放在电线上呢?如果客户端创建空数组,则204是愚蠢压缩的一种形式。如果客户端null改为使用,则会打开一个完全不同的蠕虫罐。


fla*_*Zer 6

根据 Microsoft:ASP.NET Core Web API 中的控制器操作返回类型,向下滚动到几乎底部,您会发现以下关于与数据库中未找到的对象相关的 404 的简介。在这里,他们建议 404 适合空数据。

在此输入图像描述


Vil*_*ite 6

长话短说:

  • 如果在 处找不到用户/users/9,您应该返回 404。
  • 如果在 处找不到用户/users?id=9,您应该返回 204。

长版:

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

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

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

此后我们决定对代码进行两处更改:

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

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

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

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

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

任何参与其中的人都会立即清楚 9 是一个 ID,而不是某个任意数字。在这样一个基本示例中,这一点似乎没有实际意义,但请考虑一个使用 GUID 作为行 ID 或允许您通过人名获取数据的系统,甚至是一个返回特定邮政编码而不是行 ID 信息的系统。如果所有参与的开发人员一眼就知道该标识参数是名字、姓氏、全名还是邮政编码而不是 ID,那么这对所有参与的开发人员来说都是有用的。


小智 5

看了问题之后,您不应该使用404为什么?

根据RFC 7231,正确的状态码为204

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

1.-资源是: /users

2.- /users/8不是资源,这是:/users具有route参数的资源8,消费者可能无法注意到它并且不知道差异,但是发布者知道并且必须知道这一点!...因此他必须为消费者返回准确的响应。期。

所以:

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

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

204是:我找到了资源,执行了逻辑,但是我没有使用route参数中给定的条件找到任何数据,因此我无法向您返回任何信息。抱歉,请验证您的条件,然后再次致电给我。

200:好的,我找到了资源,执行了逻辑(即使当我不强迫我返回任何东西时)也可以随意使用它。

205:(GET响应的最佳选择)我找到了资源,执行了逻辑,为您准备了一些内容,请很好地使用,哦,如果您要在视图中共享此内容,请刷新视图显示它。

希望能帮助到你。

  • 您从哪里想到资源是“/users”而不是“/users/8”?那是非常不正确的。它们都是*资源,都由 URI(统一**资源**标识符)表示。 (2认同)