例如,您为用户/9运行一个GET请求,但没有id为#9的用户。 哪个是最佳响应码?
200好了 202年接受 204无内容 400错误请求 404未找到
例如,您为用户/9运行一个GET请求,但没有id为#9的用户。 哪个是最佳响应码?
200好了 202年接受 204无内容 400错误请求 404未找到
当前回答
这里有两个问题。一个在标题中,一个在例子中。我认为,这在一定程度上导致了关于哪种反应是合适的争议。
问题标题询问空数据。空数据仍然是数据,但不等于没有数据。因此,这意味着请求一个结果集,即一个列表,可能来自/users。如果一个列表是空的,它仍然是一个列表,因此204(无内容)是最合适的。您刚刚请求了一个用户列表,并得到了一个列表,它只是碰巧没有内容。
相反,所提供的示例询问了一个特定的对象,一个用户/users/9。如果没有找到用户#9,则不返回任何用户对象。您请求一个特定的资源(一个用户对象),但由于没有找到而没有得到它,因此404是合适的。
我认为解决这个问题的方法是,如果您可以在不添加任何条件语句的情况下使用响应,那么使用204,否则使用404。
在我的例子中,我可以迭代一个空列表而不检查它是否有内容,但是我不能在一个空对象上显示用户对象数据而不破坏一些东西或添加一个检查来查看它是否为空。
当然,如果适合您的需要,您可以使用空对象模式返回一个对象,但这是另一个线程的讨论。
其他回答
TL; diana:
如果在/users/9上没有找到用户,则应该返回404。 如果在/users中没有找到用户?如果Id =9,则应该返回204。
长版:
在回顾了我自己对这些状态代码的使用和本文中的示例之后,我不得不说,如果在/users/9的url上没有找到用户#9,404是适当的响应。
今天在我的系统中,我们的Application Insights日志中充满了数百条记录的404错误,这使我们的日志变得混乱,因为我们决定在/users/9没有相关数据时返回404错误。然而,这并不意味着我们在设置响应时的方法是不正确的,相反,我认为这意味着我们在设置路由时的方法是不正确的。
如果您希望端点获得大量流量,并且担心记录太多404错误,那么您应该更改路由以符合您想要的状态码,而不是强制使用不适当的状态码。
我们已经决定对我们的代码做2个更改:
通过expect /users改变我们的工作路线?id = 9 将我们的错误代码更改为204,这样404就不会填满我们的AI日志。
最后,API的架构师需要了解他们的API将如何被使用,以及哪种路由将适合于该用例。
我相信在/users/9的情况下,您请求的资源是用户本身,用户#9;您要求服务器响应一个标识为“9”的对象,该对象恰好存在于包含单词“user”的路径中。如果没有找到该对象,则应该得到404。
但是,如果调用/users?id=9,我觉得你所请求的资源是用户控制器,同时也提供了更多的专一性,这样它就不会返回所有用户的完整列表。您要求服务器响应一个可以通过查询字符串中定义的ID号识别的特定用户。因此,如果没有找到数据,204对我来说是有意义的,因为即使没有找到数据,控制器也是。
查询字符串方法还完成了一些我认为不仅有助于API开发人员,而且有助于客户端开发人员(特别是初级开发人员或继承这段代码或调用它的代码的未来开发人员):
It becomes immediately clear to anyone involved that 9 is an ID, not some arbitrary number. This point may seem moot in such a basic example, but consider a system that uses GUIDs as row ID's or allows you to get data by a person's name, or even a system that is returning info for specific ZIP/postal codes instead of row ID's. It would be useful for all developers involved if, at a glance, they knew whether that identifying parameter was a first, last, full name, or a ZIP/postal code instead of an ID.
这个话题中的答案(在撰写本文时已经有26个)完美地说明了开发人员理解他们正在使用的构造的语义是多么重要。
如果不理解这一点,那么响应状态代码是响应的属性而不是其他属性就不明显了。这些代码存在于响应的上下文中,它们在此上下文中之外的含义是未定义的。
响应本身就是请求的结果。请求对资源进行操作。资源、请求、响应和状态代码是HTTP的结构,就HTTP而言:
HTTP提供了与资源(第2节)交互的统一接口,无论其类型、性质或实现如何,通过操作和传输表示(第3节)。
换句话说,响应状态码的范围受到一个接口的限制,该接口只关心一些目标资源,并处理用于与这些资源交互的消息。服务器应用程序逻辑超出了范围,您使用的数据也不重要。
当使用HTTP时,它总是与资源一起使用。资源被以太转移或操纵。在任何情况下,除非我们在量子世界中,资源要么存在要么不存在,不存在第三种状态。
如果发出HTTP请求来获取(传输)资源的表示(如本问题中所示),而资源不存在,则响应结果应该显示一个带有相应404代码的失败。目标-获取表示-没有达到,资源没有找到。在HTTP上下文中不应该有对结果的其他解释。
RFC 7231超文本传输协议(HTTP/1.1):语义和内容,在这里多次提到,但主要是作为状态码描述的参考。我强烈建议通读整个文档,而不仅仅是第6节,以便更好地理解HTTP接口及其组件的作用域和语义。
为什么不用410呢?它表示所请求的资源不再存在,客户端希望永远不会对该资源发出请求,在您的例子中是users/9。
你可以在这里找到更多关于410的详细信息:https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
为了总结或简化,
2xx:可选数据:格式良好的URI: Criteria不是URI的一部分:如果Criteria是可选的,可以在@RequestBody和@RequestParam中指定,应该导致2xx。例如:按名称/状态过滤
标准是URI的一部分:如果标准是强制性的,只能在@PathVariable中指定,那么它应该导致4xx。例如:按唯一id查找。
对于所问的情况: "users/9"将是4xx(可能是404) 但是对于“用户”呢?Name =superman”应该是2xx(可能是204)
这样的事情可能是主观的,双方都有一些有趣和各种扎实的论点。然而,(在我看来)为丢失的数据返回404是不正确的。这里有一个简单的描述来说明这一点:
请求:能给我一些数据吗? 资源(API端点):我将在这里为您获取请求[发送潜在数据的响应]
没有问题,找到了端点,找到了表和列,因此查询了DB,并“成功”返回了数据!
现在,无论“成功响应”是否有数据都不重要,您要求“潜在”数据的响应,并且具有“潜在”数据的响应得到了满足。Null,空等是有效的数据。
200只代表我们的请求成功了。我正在请求数据,HTTP/REST没有任何问题,作为数据(尽管为空)返回我的“数据请求”是成功的。
返回一个200,让请求者在每个特定场景下处理空数据!
想想这个例子:
请求:查询用户ID为1234的“违规”表 资源(API端点):返回一个响应,但数据为空
此数据为空是完全有效的。这意味着用户没有违规行为。这是200,因为它是有效的,然后我可以这样做:
你没有违规,吃个蓝莓松饼!
如果你认为这是404,你在说什么?无法发现用户的违规行为?从语法上讲,这是正确的,但在REST世界中,成功或失败是关于请求的,这是不正确的。该用户的“违规”数据可以成功找到,没有违规-一个实数代表有效状态。
(厚颜无耻的注意。)
在你的标题中,你下意识地认为200是正确的回答:
对于有效请求但空数据,正确的REST响应代码是什么?
在选择使用哪种状态码时,抛开主观性和棘手的选择,以下是一些需要考虑的事情:
一致性。如果您使用404表示“无数据”,则在每次响应返回无数据时使用它。 同一个状态不要有多个意思。如果在没有找到资源时返回404(例如API端点不存在等),那么也不要因为没有返回数据而使用它。这只会让应对反应变成一种痛苦。 仔细考虑上下文。什么是“请求”?你说你想达到什么目的?