在找不到REST资源时返回404是否正确?

假设我有一个简单的Jersey REST资源,如下所示:

@Path("/foos") public class MyRestlet extends BaseRestlet { @GET @Path("/{fooId}") @Produces(MediaType.APPLICATION_XML) public Response getFoo(@PathParam("fooId") final String fooId) throws IOException, ParseException { final Foo foo = fooService.getFoo(fooId); if (foo != null) { return Response.status(Response.Status.OK).entity(foo).build(); } else { return Response.status(Response.Status.NOT_FOUND).build(); } } } 

基于上面的代码,返回NOT_FOUND状态( 404 )是否正确,或者我应该返回204 ,还是其他一些更合适的代码?

提前谢谢了!

在这种情况下,404响应非常典型,API用户可以轻松使用。

一个问题是,由于未找到特定实体,或者由于URI中的结构问题,客户端难以判断他们是否获得了404。 在您的示例中, /foos/5可能返回404,因为id = 5的foo不存在。 但是, /food/1将返回404,即使存在id=1 foo(因为foos拼写错误)。 换句话说,404表示构造错误的URI或对不存在的资源的引用。

当您有一个引用多个资源的URI时,会出现另一个问题。 通过简单的404响应,客户端不知道找不到哪个引用的资源。

通过在响应主体中返回附加信息以使调用者确切地知道未找到的内容,可以部分地缓解这两个问题。

是的,为未找到的资源返回404是很常见的。 就像一个网页,当它找不到时,你得到一个404.它不仅仅是REST,而是一个HTTP标准。

每个资源都应该有一个URL位置。 URL不需要是静态的,它们可以是模板化的 。 因此,实际请求的URL可能没有资源。 服务器有责任从模板中分解URL以查找资源。 如果他们的资源不存在,那就是“找不到”

这是来自HTTP 1.1规范

404未找到

服务器未找到与Request-URI匹配的任何内容。 没有说明该病症是暂时的还是永久性的。 如果服务器通过一些内部可配置的机制知道旧资源永久不可用且没有转发地址,则应该使用410(Gone)状态代码。 当服务器不希望确切地说明请求被拒绝的原因,或者没有其他响应适用时,通常会使用此状态代码。


这是204

204没有内容

服务器已完成请求但不需要返回实体主体,并且可能希望返回更新的元信息。 响应可以包括实体标头forms的新的或更新的元信息,如果存在,应该与所请求的变体相关联。

如果客户端是用户代理,则它不应该从导致请求发送的文档视图中更改其文档视图。 此响应主要用于允许在不导致更改用户代理的活动文档视图的情况下进行操作的输入,尽管任何新的或更新的元信息应该应用于当前在用户代理的活动视图中的文档。

204响应绝不能包含消息体,因此总是在头字段之后的第一个空行终止。

通常在更新或创建表示时使用204,并且不需要发回响应主体。 在POST的情况下,您可以只发回新创建的资源的位置。 就像是

 @POST @Path("/something") @Consumes(...) public Response createBuzz(Domain domain, @Context UriInfo uriInfo) { int domainId = // create domain and get created id UriBuilder builder = uriInfo.getAbsolutePathBuilder(); builder.path(Integer.toString(domainId)); // concatenate the id. return Response.created(builder.build()).build(); } 

created(URI)将使用Location头中新创建的URI发回响应。


添加到第一部分。 您只需要记住,来自客户端的每个请求都是访问资源的请求,无论是获取资源还是使用PUT进行更新。 资源可以是服务器上的任何内容。 如果资源不存在,那么一般的响应就是告诉客户端我们找不到该资源。

扩展您的示例。 假设FooService对数据库FooService不满。 数据库中的每一行都可以被视为资源。 并且每个行(资源)都有一个唯一的URL,就像foo/db/1可能找到一个带有主键1的行。如果找不到id,那么该资源“Not Found”

4XX错误代码表示来自客户端的错误。
当您将静态资源请求为图像或html页面时,返回404响应有意义:

HTTP 404未找到客户端错误响应代码表示服务器找不到所请求的资源。 导致404页面的链接通常称为断开或死链接,并且可能会受到链接损坏。

当您向客户端提供一些REST方法时,您依赖于HTTP方法,但您不应将REST服务视为简单资源。
对于客户端,REST方法中的错误响应通常处理接近其他处理的错误。

例如,要在REST调用或其他地方捕获错误,客户端可以使用catchError()

我们可以用这种方式编写代码(在TypeScript / Angular 2中作为示例代码),将error handling委托给一个函数:

 return this.http .get("/api/foos") .pipe( catchError(this.handleError) ) .map(foo => {...}) 

问题是任何HTTP错误(5XX或4XXX)都将在catchError()回调中终止。
它可能真的使REST API响应误导客户端。

如果我们与编程语言并行,我们可以将5XX / 4XX视为exception流​​程。
通常,我们不会因为找不到数据而抛出exception,因为找不到数据并且找到了数据,所以我们抛出exception。
对于REST API,我们应该遵循相同的逻辑。

如果找不到实体,则在两种情况下返回OK是完全正常的:

 @GET @Path("/{fooId}") @Produces(MediaType.APPLICATION_XML) public Response getFoo(@PathParam("fooId") final String fooId) throws IOException, ParseException { final Foo foo = fooService.getFoo(fooId); if (foo != null){ return Response.status(Response.Status.OK).entity(foo).build(); } return Response.status(Response.Status.OK).build(); } 

客户端可以根据结果存在或丢失来处理结果。
我不认为返回204会带来任何有用的价值。
HTTP 204文档指出:

客户端无需离开当前页面。

但是请求REST资源,特别是通过GET方法,并不意味着客户端是关于终止工作流(使用POST / PUT方法更有意义)。

该文件还增加了:

常见的用例是作为PUT请求的结果返回204,更新资源,而不改变显示给用户的页面的当前内容。

我们真的不是这种情况。

经典浏览的一些特定HTTP代码与REST API的返回代码(201,202,401,以及……等)完美匹配,但情况并非总是如此。 因此,对于这些情况,我宁愿通过使用更通用的代码来保持简单,而不是扭曲原始代码: 200