【问题标题】:What is the proper REST response code for a valid request but an empty data?有效请求但空数据的正确 REST 响应代码是什么?
【发布时间】:2019-02-21 18:55:22
【问题描述】:

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

  • 200 正常
  • 202 已接受
  • 204 无内容
  • 400 错误请求
  • 404 未找到

【问题讨论】:

  • 提示:你找到用户 9 了吗?
  • 提示 2:所以用户 9找不到
  • @IMB 谁在说 204? “无内容”表示您要查找的实体存在,但没有表示。例如,如果 id 为 15 的博客没有 cmets,并且您不想为 15 号博客的 cmets 返回一个空列表:“/blog/15/cmets”将返回 NoContent。另一方面,如果博客 15 确实存在,则“404 Not Found”更合适。
  • @Crisfole 你不是说 "。另一方面,如果博客 15 存在,'404 Not Found' 更合适"
  • 我肯定做过@gdoron! :) 谢谢。遗憾的是,我大约晚了三年来编辑和修复它。

标签: rest http api-design


【解决方案1】:

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

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

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

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

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

此外,许多客户端框架通过抛出异常来响应 404,并且不再询问任何问题。这迫使客户端开发人员捕获该异常,对其进行评估,然后根据该异常决定是否将其记录为错误,例如监控组件或是否忽略它。这对我来说也不好看。

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

不过,我仍然更喜欢 204 或 200 的空响应。这样,请求的技术执行状态与请求的逻辑结果是分开的。 2xx 表示“技术执行ok,这是结果,处理一下”。

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

另一个简单的类比:“未找到结果”返回 404 就像在 SQL 查询未返回任何结果时抛出 DatabaseConnectionException。它可以完成工作,但是有很多可能的技术原因会引发相同的异常,然后会被误认为是有效的结果。

另一个角度:从操作的角度来看,404 可能是有问题的。由于它可以指示连接问题而不是有效的服务响应,因此我不希望在我的指标/仪表板中出现波动数量的“有效”404,这可能隐藏应该调查和修复的真正技术问题。

【讨论】:

  • 技术“未找到”的原因也称为服务器错误。那些应该在500年代。具体来说:“找不到服务”是503 Service Unavailable
  • 提问者还询问了一个特定资源:单个用户(不是/users 路由,而是/users/9,即“被称为#9 的用户”),所以你的'空结果set' 比较没有意义。 404 表示该对象不存在。
  • 404 仅表示未找到请求的 资源(在本例中为用户号 9)。它与是否触发应用程序代码无关,与后端应用程序是否响应无关。问题是关于网络服务器的,问题中没有提到反向代理。
  • 这个答案的推理非常错误。
  • 404:客户端能够与给定的服务器通信,但服务器找不到请求的内容。字面意思是:收到的请求,它很好并且格式正确(错误请求 400),它是经过身份验证或公开的(未经授权的 401/禁止 403),不需要付款(需要付款 402),请求方法很好(方法不允许 405 ),可以满足请求accept(不可接受的406)。用户获取资源时应使用 200 Ok。空不是资源。 400 范围用于客户端错误 500 范围用于服务器错误 简而言之:您的推理不正确。
【解决方案2】:

TL;DR:使用404

This Blog。解释得很好。

204上博客的cmets总结:

  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的定义

【讨论】:

  • 注:200s内的响应码表示成功。 400s 中的响应代码表示失败。总结,第一点和第二点,是关于204 响应代码(无内容)。
  • -1 因为我强烈反对将 404 作为对没有记录可返回的 成功 调用的响应。作为为非 Web 应用程序处理 API 的开发人员,我浪费了数小时联系 API 的开发人员以追查为什么我调用的 API 端点不存在,而事实上它确实存在,只是不存在要报告的数据。关于 204 对浏览器不是特别有用的问题,这有点像摇尾巴,因为我们智能设备领域中 API 端点的大多数使用都不是基于浏览器的,而那些可能使用 AJAX 的。不过很抱歉拿走分数。
  • @MatthewPatrickCashatt 您可以随意投反对票。我现在终于明白为什么人们不赞成我,但理由仍然是错误的。收到 404 并不意味着该路线没有意义,这意味着该位置没有资源。句号。如果您在此类用户不存在时请求 /badurl/user/9,则这是正确的。开发人员可以通过添加比“未找到”更好的原因短语来提供帮助,但这不是必需的。
  • @Crisfole 基于W3 definition of 404,特别是The server has not found anything matching the Request-URI,我倾向于不同意(尽管不反对,请继续阅读)。 Web/应用程序服务器实际上已经找到了一个匹配请求 URI 的动作,尽管 db 服务器没有。然而,它也写着This status code is commonly used when [...] no other response is applicable,所以我认为这在一定程度上验证了它的用法(即使我不同意/不喜欢它)。
  • 我认为您并没有解决我要表达的观点:404 非常令人困惑。依赖调用者检查原因短语或响应正文意味着您不信任状态代码,在这种情况下它没有用处。
【解决方案3】:

起初,我认为 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 匹配,用户 Kyle 不是可用资源,因此 404 仍然适用。它不是一个 搜索查询,是动态url直接引用,所以是404。

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

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

【讨论】:

  • 将我的重心放在这种风格的 REST API 后面。除非通过调用 /users 或 /users?name=kyle 告知客户端将存在资源,否则任何客户端都不应请求 /users/kyle
  • 这是我最认同的答案。我希望 API 如何工作的完美示例。 @GaryBarker 的评论也很完美。当您通过 ID 查找某些东西并且它不存在时,这是一个错误。在拨打电话之前,您应该知道 ID 存在。主要是因为获得一些“成功”的空响应只会将错误推向更远的地方,可能是因为在执行 user.name 或其他操作时某些“无法读取未定义的属性名称”。
  • IMO 会产生 404,因为这是一个无效请求:Kyle 不存在,因此也无法搜索他的朋友。
  • 不是搜索查询,是动态url直接引用,所以是404。这个。
  • @JustusRomijn 我(当然)同意你的看法。我可能会再添加一条我认为是此处辩论的关键的线:GET /usrs/john 404 Not found。开发人员无法区分粗手指路线和失踪人员。这就是为什么我推广GET /users/kyle 404 No such userGET /usrs/john 404 Not found
【解决方案4】:

如果预计资源存在,但它可能是空的,我认为只获得 200 OK 并表示该资源是空的可能更容易。

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

我只是将 204 No Content for PUTs 和 DELETEs 留下,这可能是真的没有有用的表示的情况。

如果 /thing/9 真的不存在,404 是合适的。

【讨论】:

  • 听起来您更喜欢使用称为 RPC 的更抽象的形式针对 API 进行编程。 RPC 方式不是通过密切关注动词和基于资源的 url(例如 customers/1/addressbook)来访问资源,而是调用类似 GetCustomerAddressBook 的端点,然后接收数据或基本上为空,而不必担心HTTP。两者各有利弊。
  • @The Muffin Man,我不确定您如何假装知道我更喜欢 REST 还是 RPC,也不知道为什么它与关于返回 HTTP GET 请求的状态代码的讨论相关.
  • 我在使用 204 时遇到了一些可怕的缓存问题。Chrome 会奇怪地处理请求,不会在网络中显示任何内容并缓存以前的结果。即使有世界上所有的无缓存标头。我同意这个答案,200 似乎是最好的,将一个空数组/对象传递给用户。
【解决方案5】:

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

对于对象存在,但没有数据,204 No Content 将是合适的。我认为在您的情况下,该对象确实 not 存在。

【讨论】:

    【解决方案6】:

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

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

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

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

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

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

    【讨论】:

      【解决方案7】:

      总结或简化,

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

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

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

      【讨论】:

        【解决方案8】:

        w3发帖,

        200 OK

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

        202 接受

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

        204 无内容

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

        400 错误请求

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

        401 未经授权

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

        404 未找到

        服务器没有找到任何匹配 Request-URI 的东西。没有说明这种情况是暂时的还是永久性的

        【讨论】:

        • w3 帖子是关于 HTTP 状态码的。 HTTP 与 REST 不同。 REST 主要但不一定使用 HTTP 作为传输协议。 404 是 HTTP 传输错误代码。如果 REST 和 HTTP 一样,不应该叫 HTTP 吗?
        • @anneb 正如你所说的 REST 使用 HTTP,所以这个答案完全有道理。 REST 不是 HTTP,REST 也不是协议。 REST 不需要相同(或与 HTTP 相同),这个答案没有意义。
        • @Koray Tugay:谷歌搜索也使用http,所以根据这个答案谷歌搜索应该响应http状态404,如果没有匹配的搜索?
        • @anneb 您提到的 Google 搜索是 RESTful 应用程序吗?我不这么认为。因此答案是否定的。回到最初的问题和这个答案,而不是掉进兔子洞。如果有一天谷歌搜索创建了一个 RESTful API(或者它可能已经有,我不知道)它可能会在找不到结果时返回 204 No Content .不是404,它有你的结果,但它没有内容..
        【解决方案9】:

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

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

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

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

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

        【讨论】:

          【解决方案10】:

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

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

          在上面的回答中,我发现了一个小误解:

          1.- 资源是:/users

          2.- /users/8 不是资源,这是:带有路由参数8 的资源/users,消费者可能没有注意到它并且不知道区别,但发布者知道并且必须知道这一点!。 ..所以他必须为消费者做出准确的回应。期间。

          所以:

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

          这里的重点是:404连处理内部逻辑的资源都没有找到

          204 是:我找到了资源,执行了逻辑,但我没有使用您在路由参数中给出的标准找到任何数据,所以我无法向您返回任何内容。抱歉,请验证您的条件并再次致电给我。

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

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

          希望对你有帮助。

          【讨论】:

          • 您从哪里想到资源是/users 而不是/users/8?那太不正确了。它们都都是资源,它们都由URI(统一的resource标识符)表示。
          【解决方案11】:

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

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

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

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

          如果服务器通过给定的 URL 找到资源,它的 内容 是什么并不重要——2G 的数据、null、{}、[]——只要它存在,它将是 200。但如果服务器不知道此类实体,则预计会返回 404“未找到”。

          一个困惑似乎来自开发人员,他们认为如果应用程序具有特定路径形状的处理程序,则它不应该是错误。在 HTTP 协议看来,只要服务器上没有与请求的 URL(请求的 MP3 文件、网页、用户对象等),将返回有效内容(空或其他),它必须是 404(或 410 等)。

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

          示例 1:

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

          示例 2:

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

          示例 3:

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

          【讨论】:

            【解决方案12】:

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

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

            【讨论】:

            【解决方案13】:

            我会说,两者都不合适。 如前所述——例如@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,其中 service 向 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 识别的操作:如果完全错误则返回REST:ERROR(例如retrun/test 之类的拼写错误),或者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 服务器可以在其自身范围内提供的信息:即,是否找到服务来处理请求。

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

            【讨论】:

              【解决方案14】:

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

              6.5.4。 404 未找到 404 (Not Found) 状态码表示源服务器没有 找不到目标资源的当前表示或不是 愿意透露一个存在。 404 状态码不 表明这种缺乏代表权是暂时的还是 永恒的; 410 (Gone) 状态码优先于 404 原始服务器可能通过一些可配置的方式知道, 这种情况很可能是永久性的。 默认情况下,404 响应是可缓存的;即,除非另有说明 由方法定义或显式缓存控件指示(请参阅 [RFC7234] 的第 4.2.2 节)。

              而引起质疑的主要是上述上下文中资源的定义。 根据相同的 RFC(7231),资源的定义是:

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

              因此,据我了解,404 状态代码不应用于成功的 GET 请求且结果为空。(例如:特定过滤器没有结果的列表)

              【讨论】:

              • 我同意这个评估,但这不是被问到的。如果您要一个列表,并且它是一个空列表,那么该空列表仍然存在。问题是,单件呢?
              【解决方案15】:

              根据 Microsoft:Controller action return types in ASP.NET Core web API,向下滚动几乎到底部,您会发现以下关于 404 的简介,该内容与数据库中未找到的对象有关。在这里,他们建议 404 适合空数据。

              【讨论】:

                【解决方案16】:

                这样的事情可能是主观的,双方都有一些有趣的和各种可靠的论据。但是 [在我看来]为丢失的数据返回 404 是不正确的。为了清楚起见,这里有一个简化的描述:

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

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

                现在 - “成功的响应”是否有数据并不重要,您要求响应“潜在”数据,并且“潜在”数据的响应得到满足。 Null、empty 等是有效数据。

                200 只是意味着我们所做的任何请求都是成功的。我正在请求数据,HTTP/REST 没有出现任何问题,并且由于返回了数据(尽管为空),我的“数据请求”成功。

                返回 200 并让请求者处理每个特定场景需要的空数据!

                考虑这个例子:

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

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

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

                如果您认为这是 404,您在说明什么?找不到用户的违规行为?现在,在语法上这是正确的,但在 REST 世界中它是不正确的,成功或失败与请求有关。可以成功找到该用户的“违规”数据,违规次数为零 - 表示有效状态的实数。


                [厚颜无耻的笔记..]

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

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


                无论主观性和棘手的选择如何,在选择使用哪个状态码时都需要考虑以下几点:

                1. 一致性。如果您将 404 用于“无数据”,每次响应都不会返回任何数据。
                2. 不要将同一状态用于多个含义。如果您在未找到资源时返回 404(例如 API 端点不存在等),那么 不要 也将它用于不返回数据。这只会让处理响应变得很痛苦。
                3. 仔细考虑上下文。什么是“要求”?你说你想要达到什么目标?

                【讨论】:

                  【解决方案17】:

                  正如许多人所说,404 具有误导性,它不允许客户端区分请求 uri 是否不存在,或者请求的 uri 是否无法获取请求的资源。

                  200 状态应该包含资源数据 - 所以它不是正确的选择。 204 状态的含义完全不同,不应用作 GET 请求的响应。

                  由于某种原因,所有其他现有状态均不适用。

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

                  这将是 2xx 状态,因为找不到 ID 不应被视为客户端错误(如果客户端知道服务器数据库中的所有内容,他们就不需要向服务器询问任何内容,不是吗? )。此专用状态将解决与使用其他状态有关的所有问题。

                  唯一的问题是:我如何让 RFC 接受它作为标准?

                  【讨论】:

                  • 你先写一个草稿。不过,我认为这不会引起关注。
                  【解决方案18】:

                  只是一位曾多次在这种情况下苦苦挣扎的开发人员的补充。您可能已经注意到,当特定资源不存在时,是否返回 404 或 200 或 204 始终是一个讨论。上面的讨论表明,这个主题非常混乱并且基于意见(虽然存在 http-status-code 标准)。 我个人建议,因为我猜它还没有被提及,无论你如何决定在你的 API 定义中记录它。当然,当客户端开发人员使用您的特定“REST”-api 来使用他/她关于 Rest 的知识并期望您的 api 以这种方式工作时,他/她会想到。我猜你看到了陷阱。因此,我使用了一个自述文件,其中我明确定义了在哪些情况下我使用哪些状态代码。这并不意味着我使用一些随机定义。我总是尝试使用标准,但为了避免这种情况,我记录了我的用法。在某些特定情况下,客户可能会认为您错了,但正如文档所记录的那样,没有必要进行额外的讨论,这可以为您和开发人员节省时间。

                  对 Ops 问题的一句话:当我回想起开始开发后端应用程序并且我在控制器路由中配置了错误以便不调用我的控制器方法时,我总是会想到 404 代码。考虑到这一点,我认为如果请求确实在 Controller 方法中到达您的代码,则客户端执行了有效请求并且找到了请求端点。所以这是一个不使用 404 的指示。如果 db 查询返回未找到,我返回 200 但正文为空。

                  【讨论】:

                    【解决方案19】:

                    TL;DR:

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

                    加长版:

                    在查看了我自己对这些状态代码的使用情况以及这篇文章中的示例之后,我不得不说,如果在 /users/9 的 URL 处未找到用户 #9,则 404 是适当的响应。

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

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

                    我们决定对我们的代码进行 2 处更改:

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

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

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

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

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

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

                    【讨论】:

                      【解决方案20】:

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

                      【讨论】:

                        【解决方案21】:

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

                        【讨论】:

                        • 如果您有后端错误,您不应该返回 404。
                        【解决方案22】:

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

                        2xx:

                        此类状态码表示客户端的请求被成功接收、理解、接受。

                        4xx:

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

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

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

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

                        【讨论】:

                          【解决方案23】:

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

                          如果没有这种理解,响应状态代码可能并不明显是响应的属性而不是其他属性。这些代码存在于响应的上下文中,它们在此上下文之外的含义是未定义的。

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

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

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

                          当使用 HTTP 时,它总是与资源一起使用。资源被以太转移或操纵。无论如何,除非我们在量子世界中,否则资源要么存在,要么不存在,不存在第三态。

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

                          RFC 7231 Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content,这里多次提到,但主要是作为状态码描述的参考。我强烈建议通读整个文档,而不仅仅是第 6 节,以更好地理解 HTTP 接口及其组件的范围和语义。

                          【讨论】:

                            【解决方案24】:

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

                            您可以在此处找到有关 410 的更多详细信息:https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

                            【讨论】:

                            • '客户应该永远不会提出请求' - 如果该用户稍后被创建,您的回答表明您可以保证该用户永远不会存在,这是一个非常大胆的假设并且可能是错误的
                            • 霍莉说的。补充一点:即使用户存在并被删除,410 也是错误的,因为如果用户被取消删除怎么办? (哪种是稍后创建的特例。)
                            • 因为 410 应该是永久的情况。 restapitutorial.com/httpstatuscodes.html
                            【解决方案25】:

                            如果您仅仅因为没有响应数据而返回,那么对于任何客户端来说,404 都会非常令人困惑。

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

                            【讨论】:

                            • 这不是标准的定义方式,也不是绝大多数 HTTP 应用程序的工作方式。
                            【解决方案26】:

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

                            如果你使用404,你怎么知道是找不到api还是找不到你数据库中的记录?

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

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

                            200 正常

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

                            【讨论】:

                            • 您可能更喜欢它,但它不正确。
                            • 感谢您的意见@Evert。假设我的 Car 对象表示为 JSON {id, model, year} 以使其简单,因此只是一个具有简单字段的 JSON 对象。如果汽车 1 不存在,您是否介意澄清如果我发出 GET: /uri/to/cars/carid (/uri/to/cars/1) 我应该得到什么?我的意思是我应该按照适当的做法恢复状态和身体?非常感谢
                            • 你至少应该发出一个404,也许是更专业的410,对于正文,我建议使用常见的错误格式,例如RFC 7807。
                            【解决方案27】:

                            在这种情况下,Ruby on Rails404 Not Found 响应。

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


                            编辑

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

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

                            • 200 正常
                            • 204 无内容

                            如果您使用 200 OK : 响应正文应为 empty json :[]{}

                            如果您使用204 OK响应正文应为空。

                            【讨论】:

                              猜你喜欢
                              • 1970-01-01
                              • 2013-06-20
                              • 2012-03-13
                              • 1970-01-01
                              • 2011-09-01
                              • 1970-01-01
                              • 2021-08-11
                              • 1970-01-01
                              相关资源
                              最近更新 更多