对于一个有效请求但是没有数据的情况,适当的REST响应代码是什么?

547
例如,您发送了一个GET请求,请求的是users/9,但是没有ID为9的用户。 最合适的响应代码是哪个?
  • 200 OK
  • 202 Accepted
  • 204 No Content
  • 400 Bad Request
  • 404 Not Found

40
提示:你找到第九个用户了吗? - Chris Pfohl
69
那么,用户9 没有被找到 - Tomasz Nurkiewicz
32
@IMB是谁在说204?"No Content"表示你正在寻找的实体存在,但没有呈现。例如,如果id为15的博客没有评论,并且您不想返回空列表以获取博客15的评论:"/blog/15/comments"将返回NoContent。另一方面,如果博客15确实存在,则更适合使用'404 Not Found'。 - Chris Pfohl
17
@Crisfole,你的意思是_“另一方面,如果博客15不存在,则应使用‘404未找到’”_。 - gdoron
22
当然,我做到了 @gdoron! :) 谢谢。可悲的是,我晚了大约三年才能编辑和修复它。 - Chris Pfohl
显示剩余12条评论
29个回答

2
作为一名曾经多次在这种情况下挣扎的开发人员,我想补充一点。你可能已经注意到,当特定资源不存在时,总是有一个关于返回404、200或204的讨论。上面的讨论表明这个主题非常令人困惑,而且基于个人观点(尽管存在HTTP状态码标准)。
我个人建议,在你的API定义中记录下你的决定,即使还没有被提到过。当然,客户端开发人员在使用你的特定“REST” API时会考虑到Rest,并期望你的API按照这种方式工作。我想你看到了陷阱。因此,我使用自述文件,其中明确定义了我在哪些情况下使用哪个状态码。这并不意味着我使用随意的定义。我总是尝试使用标准,但为了避免这种情况,我记录了我的用法。客户端可能会认为你在某些特定情况下是错误的,但由于已经记录下来了,就不需要额外的讨论,这样可以节省你和开发人员的时间。
回答Ops的问题,当我回想起开始开发后端应用程序并在控制器路由中配置错误以至于我的控制器方法没有被调用时,404是我脑海中总是出现的代码。有了这个想法,我认为如果请求确实到达了你的控制器方法中,客户端就做了一个有效的请求,并且找到了请求的终点。因此,这表明不应该使用404。如果数据库查询没有找到,我会返回200但是空的body。

1

如果仅因响应中没有数据就返回404状态码,会让任何客户端感到非常困惑。

对我来说,响应代码为200且主体为空足以表明一切都完美,但没有符合要求的数据。


这不是标准定义的方式,也不是绝大多数HTTP应用程序运行的方式。 - Evert

1
使用通用枚举对响应内容进行编码,以便客户端可以根据它进行切换并相应地分叉逻辑。我不确定您的客户端如何区分“未找到数据”的404和“未找到Web资源”的404?您不希望有人浏览到userZ/9,然后客户端像请求有效一样漫游,但没有返回数据。

1
我认为404不是正确的响应。
如果您使用404,您如何知道API未找到还是您的数据库中未找到记录?
从您的描述中,我会使用200 OK,因为您的API在没有任何问题的情况下执行了所有逻辑。它只是在数据库中找不到记录。所以,这不是API问题,也不是数据库问题,而是您的问题,您认为记录存在,但实际上并不存在。因此,在这种情况下,我会使用
200 OK
带有空响应,例如[]用于数组或{}用于对象。

2
你可能“偏爱”它,但这并不正确。 - Evert
感谢您的回复,@Evert。为了简化问题,假设我的Car对象表示为JSON {id,model,year},因此只是一个具有简单字段的JSON对象。如果汽车1不存在,您介意澄清一下我应该得到什么,如果我发出GET:/uri/to/cars/carid(/uri/to/cars/1)?我的意思是,根据适当的实践,我应该得到的状态和主体是什么?非常感谢。 - pixel
1
你应该至少发出一个 404,也许是更专业的 410,对于正文,我建议使用常见的错误格式,例如 RFC 7807。 - Evert
@Evert 我认为问题在于你假设users/9是URL。对我来说,users是URL,而/9是参数。你不能说这是错误的,因为9是REST调用中的参数。因此,在这种情况下,users URL确实存在,返回404会是错误的。你会为“users?id=9”返回404吗?最终,这是在HTML之上进行的REST调用。向REST客户端返回404表示函数调用不存在。如果你将一个技术包装在另一个技术内部,那么返回的值应该适合于外层,而不是基于内层。 - MikeKulls
1
@Evert 但归根结底,这是在HTTP之上调用的一个函数。在该函数调用中,参数为9。返回404将表明该函数不存在,而实际上它存在。为什么要止步于http?Http建立在TCP之上。为什么不争辩我们应该返回TCP错误代码?在这种情况下,我认为问题在于REST的设计者未能在此处添加一层,将HTTP错误代码转换为有效的REST错误代码。归根结底,返回404是错误的,因为该函数调用确实存在。 - MikeKulls
显示剩余5条评论

1
我们面临的是两种范式之间的紧张关系。
在HTTP和REST中,URL标识资源,“user/9”资源包含“9”。因此,HTTP应该返回404-未找到。这是RESTful的定义。稍后,您可以PUT“user/9”,然后下次获取数据时,您会得到数据。这就是HTTP和REST的设计方式。
在HTTP级别上,如果您不想要404,更好的URL将是“user?id=9”,然后找到“user”部分,函数可以进行自己的处理并返回自己的“未找到”的通知方式。
但是,为了方便指定API,使用“user/9”格式“更好”。这给我们留下了一个困境:此请求是通过HTTP发出的,(有主见的)正确的HTTP答案是404;但是通过API消费者的视角看,框架可能无法很好地处理404,并且他们希望有一个200 +“未找到”的有效负载(204对许多框架也可能存在问题)。
在已经定义的协议(HTTP)之上添加API层引起了紧张关系。当作为真正的RESTful API设计时(并正确处理它会产生的404),就没有问题了。
如果您认为“user/9”应该返回200 +“未找到”,那么您正在将“user”用作RPC端点,然后在其余URL中编码参数。我建议这是糟糕的设计,违反了RESTful规范,并且完全理解我们如何到达这里。
如果您控制两端-请根据服务器和更可能的客户端框架的约束执行有效操作。
(想想在“user/9”上执行HEAD请求的后果-您无法在响应中提供任何内容。200将表明“user/9”确实存在,而404将(正确地)指示其不存在。)

1
许多人认为404是具有误导性的,它不允许客户端区分请求uri不存在还是无法获取请求的资源。预期200状态包含资源数据,因此不是正确的选择。204状态意味着完全不同的内容,不应作为GET请求的响应使用。所有其他现有状态都不适用,因为某种原因。我在多个地方看到了这个话题被反复讨论。对我来说,显然需要一个专门的成功状态来消除该主题周围的混乱。类似于“209-没有要显示的资源”。它将成为2xx状态,因为找不到ID不应被视为客户端错误(如果客户端知道服务器DB中的所有内容,他们就不需要向服务器询问任何内容了,不是吗?)。这个专门的状态将解决使用其他状态时争论的所有问题。唯一的问题是:我该如何让RFC接受这个标准?

你可以先写一份草稿,但我认为这样做不会引起关注。 - Evert
你提到“404是误导性的,它不允许客户端区分请求URI是否存在或请求的URI是否无法获取所请求的资源。”回答:404并不是误导性的,它非常清晰明了。RFC 7231规定:“404(未找到)状态代码表示源服务器未找到目标资源的当前表示形式或不愿透露其存在。”。如果服务器由于其他原因无法获取资源,则很可能是状态代码5xx所表示的情况之一。 - Alexandre V.

1

这是我解决问题的笔记:

  1. 错误404是一个旧事物,当静态页面被提供时。因此404未找到意味着“URL不存在”
  2. 当我调用/users/{user-id}中不存在的用户ID时,我应该得到一个错误而不是成功响应。为什么:因为我期望用户ID存在,因为你从用户列表(在网站上)中获取用户ID,然后单击它,这意味着它应该存在。
  3. 最佳解决方案,但目前不可能(或者如果公司同意):
  • 使用新的错误代码来人为触发“未找到任何内容”,例如488表示“资源未找到”,意思是:“URL下的函数无法找到任何内容(在服务器或数据库中),我们引发了错误,因为您确定某些内容存在”

  • 只有在URL不正确时,404才会自动触发,这是每个服务器的常见行为。

3.1) 这将使理解和调试变得更加容易,因为:

  • 404会告诉您您的URL有误,甚至没有到达服务器

  • 另一方面,488会针对每种搜索情况(如/users/9/users?id=9/users + id_in_a_post_request_body)告诉您,由于某种原因您期望存在的用户不存在,因此您无法继续计划的工作(呈现“用户”页面)。

  1. 解决方法(当前情况下):
  • 如果找不到任何内容,请引发404错误,但编写一个描述性响应消息(不要使用默认的“未找到”,而是更像“未找到用户”

0

2
客户端不应该发出请求,如果这个用户后来被创建了,你的回答表明你可以保证这个用户永远不存在,这是一个非常大胆的假设,很可能是错误的。 - Holly
Holly所说的。补充她的观点:即使用户存在并被删除,使用410也是错误的,因为如果用户被恢复了呢?(这其实是后来创建的一种特殊情况。) - Christian Hujer
因为 410 状态码应该是一个永久性的情况。 - Akostha

-2
在这种情况下,Ruby on Rails 会响应 404 Not Found
客户端请求的资源不存在,因此使用 404 Not Found 更为合适。
编辑

我发现,在这种情况下,许多开发人员不喜欢 404未找到

如果您不想使用 404,我认为您可以使用以下两个响应代码之一:

  • 200 OK
  • 204 No Content

如果您使用 200 OK响应正文应该是空的json[]{}

如果您使用 204 OK响应正文应该是空的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接