REST API是否应该返回500 Internal Server Error以指示查询引用了不存在的对象?


39

我正在使用REST API,该API驻留在为大量IoT设备处理数据的服务器上。

我的任务是使用API​​查询服务器以收集有关所述设备的特定性能信息。

在一个实例中,我获得了可用设备及其对应标识符的列表,然后稍后使用那些标识符(GUID)向服务器查询更多详细信息。

服务器正在500 Internal Server Error对这些ID之一返回a 进行查询。在我的应用程序中,引发了异常,并且我看不到有关该错误的详细信息。如果我使用Postman更仔细地检查响应,则可以看到服务器在包含以下内容的正文中返回了JSON:

errorMessage: "This ID does not exist"

忽略服务器提供ID开头的事实-这对于开发人员是一个单独的问题。

REST API是否应返回,500 Internal Server Error以报告查询引用了不存在的对象?在我看来,HTTP响应代码应严格参考REST调用的状态,而不是API的内部机制。我希望200 OK响应中包含错误和描述,这是所讨论的API专有的。


在我看来,取决于REST调用的结构,期望值可能存在差异。

考虑以下示例:

  1. http://example.com/restapi/deviceinfo?id=123
  2. http://example.com/restapi/device/123/info

在第一种情况下,设备ID作为GET变量传递。404或500表示/restapi/deviceinfo找不到路径()或导致服务器错误。

在第二种情况下,设备ID是URL的一部分。我会更了解404 Not Found,但仍可以根据路径的哪些部分被解释为变量还是端点来争论。


您描述的这种情况是成功还是失败?
罗伯特·哈维


@RobertHarvey我的期望是API将返回有关设备的一些信息。查询本身应该已经成功,但是丢失的设备ID不会在请求级别导致失败。
JYelton

18
对我来说,不存在的ID听起来像是404。出现500个错误的最常见原因是程序员允许内部异常冒泡,以供托管服务器处理。有时确实有例外情况发生,有时只是懒惰的编程。很难说这是怎么回事。
Berin Loritsch '18

9
500名内部服务器的意思是“这是我们的错,我们搞砸了的东西”,你永远不应该瞄准这一状态返回给用户。它的目的是基本上指示一个错误-您的用户可以说在提出特定请求时得到500,然后您可以修复它。
berry120 '18

Answers:


96

我认为404响应是此处最佳的语义匹配,因为未找到您要查找的资源(由用于查询的URI表示)。在主体中返回错误有效载荷是合理的,但不是必需的。

根据RFC 2616,404状态码的定义为:

10.4.5找不到404
服务器未找到与Request-URI匹配的任何内容。没有迹象表明这种情况是暂时的还是永久的。如果服务器通过某种内部可配置的机制得知旧资源永久不可用并且没有转发地址,则应使用410(已消失)状态代码。如果服务器不希望确切显示请求被拒绝的原因,或者没有其他响应可应用时,通常使用此状态代码。


6
如果不存在的id对应于正在检索的资源,则404仅是语义匹配。
罗伯特·哈维

55
@ThomasOwens不返回任何结果的查询将返回200状态和一个空结果数组。仅当指定实际不存在的特定对象ID时,才会返回404。
肖恩·伯顿

11
@ThomasOwens:从调用方的角度来看,端点不是/questions,而是/questions/368213。该端点在您的方案中不存在。这样想:如果在/ foo / bar上执行GET而没有bar,那么为什么/ foo存在,响应为什么应该不同?
布莱恩·奥克利

17
是的,这不是服务器错误,因此我们不发送5xx。这是客户端错误-客户端要求的内容没有,因此我们发送了4xx,尤其是
404。– bdsl

7
@ThomasOwens:How do you differentiate between a 404 meaning "the query returned no results" and a 404 meaning "the endpoint does not exist"?-400错误请求
罗伯特·哈维

34

我将使用您的示例。

http://example.com/restapi/deviceinfo?id=123

如果端点返回json 数组,则最好的选择是200 OK如果没有找到结果,则使用空数组。

如果端点被设计为返回单个结果,那么我的选择是404 NOT FOUND,因为对我而言,这种端点的正确语法是:http://example.com/restapi/deviceinfo/123。我通常只将请求参数用于过滤以及端点返回数组时使用。

http://example.com/restapi/device/123/info

我认为这个问题已经在这里回答。POST或GET,更好的选择似乎404 NOT FOUND是因为123找不到资源。

在这两种情况下,我都看不出有必要解释请求未完成的原因。请求信息和HTTP代码已经说明了原因。


2
您如何区分不存在的ID和错误的URL?
罗伯特·哈维

2
@luizfzs,您也可以这样做,我看不到任何问题。在我开发的某些API中,我更喜欢在成功的PUT或DELETE中使用204(如此处所述),而无需任何响应。
Dherik

10
在该级别上,为什么区分不存在的ID和错误的URL?无论哪种方式,就HTTP而言,您仍在发出有效请求。服务器...好吧... 找不到您要寻址的资源。错误的URL并非格式错误的请求;这是对错误事情的正确要求。
cHao

6
@cHao因为作为开发人员,我想知道我的应用程序是否由于该项目不存在而失败,或者我是否不小心将我的应用程序指向了app.company.cxm / test /而不是app.company.cxm / tst /
Patrick M

7
@PatrickM:作为开发人员,您应该知道错误响应也可以包含消息正文。如果您确实需要,那就是说明性错误信息所在的地方。不要仅仅因为对胖胖的手指感到偏执就破坏语义。在HTTP级别,您是否喜欢like /itms/1234或都没关系/items/12234
cHao

27

HTTP 404 是正确的,因为服务器可以了解客户端在请求什么资源,但是它没有该资源。

您正在使用“ REST API”这一事实是关键。API的行为应类似于执行代表性状态转移,而不是执行功能。(当然,术语“ REST”已经具有更广泛的含义,但是您仍然可以在这里使用其字面含义来达到良好的效果。)客户端已请求URL描述的资源状态http://example.com/restapi/device/123/info。查询字符串(/deviceinfo?id=123)不会改变这种情况。服务器知道您正在请求传输设备123的状态,但是它无法将其识别为已知资源。因此HTTP 404

这里讨论的其他可能的响应也具有特定的含义:

  • HTTP 200-我们为您提供状态;它在响应主体中。
  • HTTP 204-我们为您提供状态;它是空白。
  • HTTP 400-我们无法告诉您您要问什么资源。修正您的网址。
  • HTTP 500-我们出故障了。不是你的错。

参见RFC 2616第。10个(视情况而定)。


我同意你的看法。如果服务器返回的是404,那将比其正在执行的操作(500)更有意义。谢谢。
JYelton

11

5xx错误通常用于指示服务器遇到错误并且无法完成请求。如果服务器接受了请求,可以成功解析它,然后执行它的工作,则不应返回5xx错误。

我不确定如果查询没有结果返回什么约定。我已经看到了您所描述的内容(一个带有消息的正文的200)以及一个404(指示未找到结果)。200可能是最有意义的-请求成功完成,并且客户端的请求或服务器在处理请求期间没有问题。主体可以向客户端传递消息。


我将把您的两个示例(http://example.com/restapi/deviceinfo?id=123http://example.com/restapi/device/123/info)视为相同-这123是一个参数。两种情况都是构造请求以获取ID为123的设备的设备信息的请求的不同方式。

首先,我将考虑授权和认证。如果用户没有适当的权限,我将适当地返回403或401。尽管它被称为“未经授权”,但我的理解是401与认证有关,而403与未经授权或被拒绝有关。但是,如果您只是想针对所有身份验证和授权错误坚持403,那么我在这里不会太挑剔。

然后,我将处理ID。根据您的示例,它看起来像是一个数字ID。如果提供了非数字值,我将返回400。如果该参数可能是有效的设备标识符,则我将继续处理。如果还有其他参数,也可以在此处进行检查。我希望响应正文包含有关为什么请求失败的适当信息。

如果所有参数均有效,我将开始处理该请求。如果系统或任何依赖项(数据库,第三方服务,另一个内部服务)不可用,我将返回5xx代码-503是特定的,但500也可以接受。无论哪种情况,我都将返回带有其他详细信息的正文。请考虑一下,如果外部依赖项报告了408请求超时,那么我会吃掉该请求并将500返回给我的客户端,仅当对我的系统的请求超时时,才允许客户端接收408。如果系统能够完成请求,我将返回200和适当的正文。

204在某些情况下可能很有用,但会阻止您发送响应正文。尤其是在API设置中,在大多数情况下,发送带有可以输入到日志记录或报告机制中的信息的响应主体似乎是正确的决定。

唯一会返回404的时间是服务器没有/deviceinfo端点或/device/:id/info端点。

我不会认为找不到的ID与找不到的ID相同。资源是特定设备的设备信息(在您的示例中)。返回404表示资源(设备信息)不存在。具有适当主体的200表示系统确实可以提供设备信息。可能有或没有具有指定ID的设备。


1
@RobertHarvey是的。没有错误。仅仅因为服务器生成了GUID并将其发送给客户端并不意味着其他操作已将其删除。请求/响应成功。该请求代表的命令或查询未返回数据。对我来说,这不是失败。这可能是一个例外,但我不认为这值得5xx。
Thomas Owens

2
如果我正在设计要查询的API,那么我将使其返回200,并带有一个包含效果的主体device: 123; status: not found;。然后,我知道该查询有效,并且该API正在告诉我有用的信息。
耶尔顿(JYelton)'18

7
@Blrfl许多网站500页的措辞都支持(尽管没有“证明”),通常是“我们犯了一个错误,并将进行调查”之类的内容。在我看来,运行正常的服务器永远不会发送500s,除非在宇宙射线的情况下。
mbrig

6
Http没有“端点”的概念,在变量和URL的其余部分之间没有相关的区分,因此也没有休息点。您可能拥有一个在正则表达式上匹配的路由系统,并将数千个URL路由到一个控制器功能,但这只是实现细节,而不是API的基本组成部分。对于get的200响应仅适用于检索请求的资源的情况。在这种情况下,客户端希望表示不存在的资源,因此404是正确的响应。
bdsl

8
正常运行的系统永远不会发送500响应。正常运行的服务器可能会发送500,因为如果它是较大系统的一部分,并且已检测到较大系统内部的错误,例如数据库已关闭,或者其他依赖于Web服务的返回无意义的结果。
bdsl

5

500系列HTTP错误表示服务器故障。除了501 Not Implemented和之外505 HTTP Version Not Supported,使用这些错误代码还意味着在稍后的时间重试请求可能会成功(尽管仅503 Service Unavailable明确说明了这一点)。理想情况下,服务器永远不应该生成这些代码之一,尽管无法编写无错误的软件并为服务器提供无限的资源意味着您将不时需要它们。

对于“对象不存在”的结果,您可能应该返回404 Not Found(当请求按名称请求对象时),或者返回200 Success空的结果正文(按属性搜索对象时)。 204 No Content看起来很诱人,但我只会在预期结果缺乏响应主体的情况下使用它。


1

作为您API的客户端,当我进行以下任一调用时:

  1. http://example.com/restapi/deviceinfo?id=123
  2. http://example.com/restapi/device/123/info

我希望取回一个DeviceInfo对象(的表示形式)(或者无论如何是某种特定类型,无论是正式类型还是仅符合已记录的“鸭子类型”约定的某种类型)。我想要一个200状态来表示我实际上已经获得一个状态,并且可以继续使用它。

对于REST API,我认为400和500状态代码就像异常一样。您可以使用它们来指示何时无法为收到的请求返回“正常”响应,因此客户端将需要做一些额外的事情,而不是处理其期望检索的信息。

这意味着,作为API使用者,我可以使用某种经过检查的休息调用函数来检索响应或引发异常。那很棒; 我的正常逻辑可以是直线代码,而且我可以像在本地代码中一样组织错误处理。意外的404将表现为“找不到资源”异常,而无需我做任何事情,而不会表现为“丢失属性”错误,当我稍后{ errorMessage: "Device 123 not found" }将其视为DeviceInfo对象时进行处理。

如果您认为找到了端点,而只有端点http://example.com/restapi/deviceinfo 没有找到,id=123因此在正文中返回200并显示一条错误消息,那么您正在创建与C函数完全相同的接口问题,它们可能会返回一个正确的结果或错误代码,或通过任意返回来指示问题的方法null。作为您的界面用户,通过“独立”渠道与常规退货指示的错误要好得多。即使HTTP 200、404和500响应从低级别的角度来看是同一通道,在这里也是如此。它们是标准化的,易于区分,因此我的REST客户端框架可以轻松打开这些状态,以将它们转换为我的语言中的正确结构。为了在JSON层(您总是说200并给我一个DeviceInfo或一条错误消息)上做同样的事情,我需要嵌入一些有关您使用的JSON模式的知识。

因此,只有当您可以返回期望类型的有效值时才使用200(这就是为什么http://example.com/restapi/search-devices?colour=blue如果没有蓝色设备,可以返回200并带有一个空数组;为什么一个空数组是一个有效数组,以及对请求“想要所有蓝色设备的详细信息”)。如果不能,请使用最合适的非200状态代码。即使“设备123不存在”是对“向我提供设备123的详细信息”的正确响应,对于服务器也不是错误,但客户端期望他们会取回a DeviceInfo并且应该不能作为正常的“这就是您要的”答复传达。


不幸的是,我也是该API的客户端,无法更改。这是怎么一个伟大的总结应该工作,虽然。
JYelton

0

您可以使用错误422无法处理的实体来区别未找到的 404 。422表示服务器可以理解请求,但不能给出正确的响应。我在类似情况下使用此代码。


4
本文更详细地介绍了如何使用422。我不认为此错误代码在这里真的适用。
罗伯特·哈维

谢谢,非常有用!我将不得不加深这个主题!
FiNeX

0

错误500通常表示请求使服务器端程序崩溃;在企业环境中,这些错误被视为一个鸡蛋,并且可以避免。

错误4xx应该向程序员发出信号,指出API端点(资源)不存在。因此,一旦到达适当的端点,此后的任何错误处理都是API程序员的责任,应妥善处理,即使用200响应的错误消息。


1
因此,您说的是“不要使用500,因为您不会使服务器崩溃?”
罗伯特·哈维

0

尽管w3指出当没有其他响应适用时使用404 ,这不是204(无内容)响应的优点吗?从处理的角度来看,该请求是有效的,并且服务器处理了该请求并产生了结果。这是成功的,它倾向于2xx的响应。该特定请求没有内容,因此204告诉用户他们的查询没有错,但那里什么也没有。

您也可以提出一个弱小的案例,即409(冲突)是适当的响应。尽管409最常用于POST,但它确实说

由于与资源的当前状态存在冲突,因此无法完成请求。仅在预期用户可能能够解决冲突并重新提交请求的情况下才允许使用此代码。响应主体应该包含足够的信息,以使用户能够识别冲突的根源。理想情况下,响应实体应包括足够的信息供用户或用户代理解决问题。但是,这可能是不可能的,也不是必需的。

可以说,所请求的id的不存在就是冲突,在系统中不存在这样的id的消息中返回足够的信息供用户识别并解决冲突。


3
不可以,只有在找到请求的资源并且其表示正好为零个字符时,对gets请求的204响应才有意义。
bdsl

0

其他答案可以解决这个问题,但是我只想指出一个500系列错误的意思是“我搞砸了”。在这种情况下,“ I”表示API,因此是未处理的服务器错误或类似错误。400系列错误表示“您搞砸了”-API的调用者发送了一些错误消息。


-4

其他用户已经提供了有效答案,可帮助您解决该问题。

但是,我建议您对RESTfulness读得太多,并且绝对要对此感到敬佩。

REST是一种反复无常的协议,因为如果您想在使用本书的同时阅读它,那么它会强制构建客户端和服务器,使其都具有特定的知识,即他们通过REST进行通信,因此从本质上讲,特定的通信协议就是不能被抽象出来。

有另一种方法:完全避开RESTfulness,并将其仅用作通信协议,别无其他。这意味着唯一需要返回的响应是“ HTTP 200 OK”和“ HTTP 500 Internal Server Error”,因为就通信协议而言,任何通信尝试都只会产生两个结果:请求成功是否交付给服务器。

交付后发生的事情与通信协议无关。因此,一旦服务器成功接收到请求并开始处理该请求,可能会发生许多错误,但是这些都是特定于应用程序的错误,与通信协议无关,也不了解任何事情。就通信协议所知,它们应该在看起来非常成功的响应有效载荷内进行通信。

因此,最重要的是,我建议返回“ HTTP 200 OK”,并且在响应有效负载(HTTP措辞中为“响应内容正文”)中包含特定于应用程序的错误代码,其中显示“找不到ID”或其他内容。


从不赞成票的角度来看,我想我一定是在伤害某些人的感情。或者他们身体的其他部位。C-:=
Mike Nakis


1
这里没伤。你错了 即使您链接到的文章也没有提及使用状态代码,这是非常错误的,以至于错误和成功看起来都是一样的。它说:“谈到趣味,重要的是要记住,API设计并不严格地涉及对客户端和服务器软件的实际影响。API的受众是将要使用它的开发人员。按照“至少要遵循的原则”。惊讶”,如果开发人员遵循与他们熟悉的其他API相同的约定,开发人员将更容易学习和理解该API。
cHao

@cHao,因此,我想说的是“ Dropbox当前使用大约10种不同的状态代码(8个错误和2个成功代码),但是我们计划在API的未来版本中减少该数量”这一部分对您。
Mike Nakis

并不是说你从中得到什么。如果他们知道自己在做什么,那么在最极端的情况下,他们会将成功减少为四个错误代码(400、401、404和500),因为他们显然关心约定。
cHao
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.