在 Rest API 中找不到处理资源

Posted

技术标签:

【中文标题】在 Rest API 中找不到处理资源【英文标题】:Handle Resource not found in Rest API 【发布时间】:2019-04-07 11:29:33 【问题描述】:

我正在 Spring Boot 中开发一个 Rest API。找不到资源实例时,以下哪项是最好的处理方式?

    @GetMapping(value="/book/id")
    public ResponseEntity<Book> getBook(@PathVariable String id)

        Book book = bookService.getBook();

        // Which is best Approach for resource instance not found ?
        if(book == null) 
            // This one
            return new ResponseEntity<>(book, HttpStatus.NO_CONTENT);
            //OR
            return  new ResponseEntity<>(book, HttpStatus.NOT_FOUND);
            //OR 
            throw new DataNotFoundException("Book with id " + id + " Does not exist");
        

        return new ResponseEntity<>(book , HttpStatus.OK);
    

我很清楚,当在 Db 中找不到资源集合时,然后传递一个空集合而不是 null,但我不清楚如何处理资源实例。

我还在 *** 上读到 HttpStatus.NOT_FOUND 应该在条件下的资源不能存在而不是在 Db 中不存在时使用。

处理这个问题的最佳方法是什么?

【问题讨论】:

虽然要求“最佳方法”主要是固执己见,但如果找不到资源,好的 REST API 应该始终使用 HTTP 404 来回答;即给定的 ID 不存在。 @Seelenvirtuose,我应该作为异常返回还是作为响应实体发送?我可以在两种情况下都设置响应状态 404 如果找不到资源,则 404 不是适当的响应,相反,无内容响应会更干净@Seelenvirtuose 【参考方案1】:

使用 Spring MVC 时,返回结果时通常有两种选择,要么使用普通对象,要么使用 ResponseEntity 类。这两个都不比另一个好。此外,您可以决定是否使用异常来分离错误处理。

鉴于此,您通过引发异常的第三种情况基本上与您的前两个选项之一相同。默认情况下,抛出异常会导致 500 Internal Server Error,但可以使用@ResponseStatus 注解进行更改,例如:

 @ResponseStatus(HttpStatus.NOT_FOUND) // Or @ResponseStatus(HttpStatus.NO_CONTENT)
 public class DataNotFoundException extends RuntimeException 

 

或者,您也可以定义异常处理程序。同样,这可以通过使用普通对象或ResponseEntity 来完成,例如:

@ResponseStatus(HttpStatus.NOT_FOUND) // Or @ResponseStatus(HttpStatus.NO_CONTENT)
@ExceptionHandler(DataNotFoundException.class)
public Book handleNotFound(DataNotFoundException ex) 
    return null;

或者:

@ExceptionHandler(DataNotFoundException.class)
public ResponseEntity<Book> handleNotFound(DataNotFoundException ex) 
    return new ResponseEntity<>(null, HttpStatus.NOT_FOUND); // Or HttpStatus.NO_CONTENT

同样,两者都不比另一个更好,您的选择主要基于个人喜好。但是,您可能应该始终使用一个。


现在,这意味着还有两个选择,要么选择HttpStatus.NOT_FOUND (404) 要么选择HttpStatus.NO_CONTENT (204)。虽然您在技术上可以使用任何一种状态,但它们具有不同的含义:

204 = 请求成功,但什么也没有。 404 = 请求不成功,资源不存在

现在,如果您请求 /book/123 并且没有 ID 为 123 的书,它可以被视为不存在的资源,因此,HttpStatus.NOT_FOUND 最有意义。

【讨论】:

【参考方案2】:

首先,我认为您的方法参数是 @PathVariable 而不是 @RequestParam(请参阅 difference between PathVariable and RequestParam here )。

其次,对于收到 404 not found 响应的客户端来说,这将是不明确,因为这意味着:

服务器没有找到任何匹配请求的地址 (URI) ( 未找到 )。这意味着您输入的 URL 错误或已过时 并且与服务器上现有的任何文档都不匹配(您可以尝试 从右到左逐渐删除 URL 组件 最终检索现有路径)。

知道你的返回类型是ResponsEntity,这样更合适:

    @GetMapping(value="/book/id")
    public ResponseEntity getBook(@PathVariable String id)

        Optional<Book> book = bookService.getBook();

        if(book.isPresent()) 
            return ResponseEntity.status(HttpStatus.OK).body(book.get());
        

        return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
    

【讨论】:

奇怪的是,你对我的回答投了反对票!!!!即使这不是我的说法,而是 REST 最佳实践,无论如何您都可以从 San Fransisco 的 Oracle 代码中观看 Effective design for RESTful AP。如果您输入错误的 URI,您也可以有 404 ;) 所以客户端将如何知道哪个 404 对应于 DB 中未找到的实体!【参考方案3】:
    如果您的端点通过 id 获取 book 并且 book 不存在,则返回 400。不要返回 404。404 是协议错误:它应该为错误的 URL 保留。现在 URL 是正确的,但 id 是错误的。 Id 几乎经常不会被猜到,而是由先前的查询返回。它不能突然消失:如果 id 错误,则请求错误。 如果您的端点按标题获取书籍并且书籍不存在,则返回 204。在这种情况下书籍不存在是绝对正常的,客户端应准备处理 204。

有人可能会争辩说 400 和 204 之间的差异是模糊的,最好总是返回 204。确实,差异可能是模糊的,但从监控的角度来看,我想知道什么时候一切正常(没有找到按标题的书)以及什么时候气味(id 没有找到任何书)。

我知道我的回答不符合 REST 指令(或者可能不符合)。我不太在乎。我只是认为404应该保留给应用程序服务器,不应该被应用程序使用。原因已在此处的其他答案中进行了说明。

总结:

404:网址错误 400:ID 错误 204:未找到,没关系

【讨论】:

【参考方案4】:

返回 404 HttpStatus 给客户端,不要浪费时间。没有人会正常请求 db 中不存在的 id。通常像 model/id 这样的客户端请求来自 针对您的收藏 [model1,model2,.....]

【讨论】:

【参考方案5】:

每当找不到资源时,您应该向客户端表明这一点,最常见的是使用 HTTP 状态代码 404 Not Found,正如您已经提到的。

对于集合,只需在响应正文中返回一个空数组(连同响应代码 200 OK,我认为这很难),返回 404 Not Found,因为资源实际存在。

请注意,这里的 202 No Content 是一个不好的选择,因为服务器没有成功地满足了请求。相反,请将此返回代码用于成功的 PUT 请求(您已更改内部数据但在响应正文中未返回任何内容)。

在大多数 API 中,您会在响应正文中遇到其他信息:

"messages":"error":["code":404,"message":"Resource not found."]

您将找到所有错误的列表及其响应代码以及信息性描述。有一点很重要:坚持 one 格式,否则对客户来说会很痛苦。大多数 API 也只使用大约 6-8 个 HTTP 响应代码。

此外,Spring 有许多实用程序可以帮助您:

@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="No such Order")
public class OrderNotFoundException extends RuntimeException 
    // ...

或者,使用以下注释创建自定义响应格式:

@ExceptionHandler( YourException.class )

【讨论】:

以上是关于在 Rest API 中找不到处理资源的主要内容,如果未能解决你的问题,请参考以下文章

Angular.js - CORS - ASP.NET - Rest API - 在 Access-Control-Allow-Origin 标头中找不到来源

Docker容器启动时在jar中找不到api-rest的主类

报错:ASP.NET Web API中找不到与请求匹配的HTTP资源

AGPBI错误,样式中找不到资源动画

在 wpf 中找不到“资源”文件

在 Next.js 应用程序中找不到 API 路由(找不到该页面)