简体   繁体   English

在 Rest API 中找不到处理资源

[英]Handle Resource not found in Rest API

I am developing a Rest API in spring boot.我正在 Spring Boot 中开发一个 Rest API。 Which of the following is the best way to handle when an instance of resource not found ?当未找到资源实例时,以下哪项是处理的最佳方法?

    @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);
    }

I am clear about that when a collection of resource not found in Db then to pass an empty collection instead of null but I am not clear what to do with an instance of resource.我很清楚,当在 Db 中找不到资源集合时,传递一个空集合而不是 null,但我不清楚如何处理资源实例。

I have also read on StackOverflow that HttpStatus.NOT_FOUND should be used when a Resource under the criteria cannot exist instead of do not exist in the Db.我也看到在计算器上那个HttpStatus.NOT_FOUND当在DB中不存在的条件下,资源不能代替存在应该被使用。

What is best approach to handle this ?处理这个问题的最佳方法是什么?

When working with Spring MVC, you usually have two choices when returning your result, either you work with plain objects, or you work with the ResponseEntity class.使用 Spring MVC 时,返回结果时通常有两种选择,要么使用普通对象,要么使用ResponseEntity类。 Neither of those is better than the other.这两者都不比另一个好。 Additionally, you can decide whether or not you separate your error handling using exceptions or not.此外,您可以决定是否使用异常来分离错误处理。

Given that, your third scenario by throwing an exception is essentially the same as one of your first two options .鉴于此,您抛出异常的第三种情况与您的前两个选项之一基本相同 By default, throwing an exception will result into a 500 Internal Server Error, but it can be changed by using the @ResponseStatus annotation, for example:默认情况下,抛出异常将导致 500 Internal Server Error,但可以通过使用@ResponseStatus注释来更改它,例如:

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

 }

Alternatively, you can also define an exception handler.或者,您也可以定义异常处理程序。 Again, this can be done by either working with plain objects or ResponseEntity , for example:同样,这可以通过使用普通对象或ResponseEntity来完成,例如:

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

Or:或者:

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

Again, neither is better than the other and what you choose is mostly based upon personal preference .同样,两者都不比另一个好,您的选择主要基于个人喜好 However, you should probably use one consistently.但是,您可能应该始终使用一个。


Now, that means that there are still two choices left, either by choosing HttpStatus.NOT_FOUND (404) or HttpStatus.NO_CONTENT (204).现在,这意味着还有两个选择,要么选择HttpStatus.NOT_FOUND (404),要么选择HttpStatus.NO_CONTENT (204)。 While you can technically use either status, they have a different meaning:虽然您可以在技术上使用任一状态,但它们具有不同的含义:

  • 204 = The request was succesful, but there's nothing. 204 = 请求成功,但什么也没有。
  • 404 = The request was not succesful, the resource does not exist 404 = 请求不成功,资源不存在

Now, if you request /book/123 and there's no book with ID 123, it could be seen as a resource that doesn't exist, and thus, HttpStatus.NOT_FOUND makes most sense.现在,如果您请求/book/123并且没有 ID 为 123 的书,则可以将其视为不存在的资源,因此HttpStatus.NOT_FOUND最有意义。

First of all I think that you mean @PathVariable and not @RequestParam for your method parameter (see difference between PathVariable and RequestParam here ).首先,我认为您的方法参数是指@PathVariable而不是@RequestParam (请参阅此处的 PathVariable 和 RequestParam 之间的区别)。

Secondly, it will be ambiguous for the client that receives the 404 not found response as this means that :其次,对于收到 404 not found 响应的客户端来说,这将是模棱两可的,因为这意味着:

The server has not found anything matching the requested address (URI) ( not found ).服务器未找到任何与请求的地址 (URI) 匹配的内容(未找到)。 This means the URL you have typed is wrong or obsolete and does not match any document existing on the server (you may try to gradualy remove the URL components from the right to the left to eventualy retrieve an existing path).这意味着您输入的 URL 是错误的或已过时的,并且与服务器上现有的任何文档都不匹配(您可以尝试从右到左逐渐删除 URL 组件以最终检索现有路径)。

Knowing that your return type is a ResponsEntity , it will be more appropriate to have this :知道您的返回类型是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();
    }
  1. If your endpoint gets book by id and the book does not exists, return 400. Do not return 404. 404 is protocol error: it should be reserved for wrong URL.如果您的端点通过 id 获取 book 并且该 book 不存在,则返回 400。不要返回 404。404 是协议错误:它应该保留给错误的 URL。 Now URL is correct but id is wrong.现在 URL 是正确的,但id是错误的。 Id almost often is not guessed, but returned by previous query. Id 几乎经常不被猜到,而是由先前的查询返回。 It cannot disappear suddenly: if id is wrong, the request is wrong.它不能突然消失:如果id错误,则请求错误。
  2. If your endpoint gets book by title and the book does not exists, return 204. That is absolutely normal that book does not exists in such case and client should be prepared to handle 204.如果您的端点按标题获取书籍并且书籍不存在,则返回 204。在这种情况下书籍不存在是绝对正常的,客户端应该准备处理 204。

Someone could argue that difference between 400 and 204 is fuzzy and better always return 204. Indeed, difference may be fuzzy, but from monitoring perspective I would like to know when everything is ok (no book found by title) and when something smells (no book found by id).有人可能会争辩说 400 和 204 之间的差异是模糊的,最好总是返回 204。确实,差异可能是模糊的,但从监控的角度来看,我想知道什么时候一切正常(没有找到书名)以及什么时候有气味(没有通过 id 找到的书)。

I know that my answer does not comply REST directives (or maybe does not comply).我知道我的回答不符合 REST 指令(或者可能不符合)。 I don't care it too much.我不太在意。 I simply think that 404 should be reserved for application server and should not be used by application.我只是认为404应该是为应用服务器保留的,不应该被应用程序使用。 Reason is already explained in other answer here.原因已在此处的其他答案中进行了解释。

Summary:概括:

  • 404: wrong URL 404:错误的网址
  • 400: wrong id 400:错误的ID
  • 204: not found and that is OK 204:没有找到 没关系

just return 404 HttpStatus to client ,do not waste time on it.No one will request id that not exist in db normally.只需将 404 HttpStatus 返回给客户端,不要浪费时间。没有人会请求正常情况下不存在于 db 中的 id。 usually client request like model/{id} come from against your Collection [model1,model2,.....]通常像 model/{id} 这样的客户端请求来自你的 Collection [model1,model2,....]

Whenever a resource cannot be found, you should indicate that to the client, most commonly using the HTTP Status Code 404 Not Found, as you already mentioned.每当找不到资源时,您应该向客户端表明,最常见的是使用 HTTP 状态代码 404 Not Found,正如您已经提到的。

For collections, simply return an empty array in the response body (alongside with response code 200 OK, this is my opinion tough), do not return 404 Not Found since the resource actually exists.对于收藏,只是返回的响应体空数组(一起响应代码200 OK,这是我的看法韧),返回404未找到,因为资源确实存在。

Please note that 202 No Content is a bad choice here, since the server has not successfully fulfilled the request.请注意,此处 202 No Content 是一个糟糕的选择,因为服务器尚未成功完成请求。 Instead, use this return code, for example, for a successful PUT request (you have changed internal data but return no content in the response body).而是使用此返回码,例如,对于成功的 PUT 请求(您已更改内部数据但在响应正文中未返回任何内容)。

In most APIs you will encounter additional information in the response body:在大多数 API 中,您会在响应正文中遇到附加信息:

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

You will find list of all errors and their response codes with informative descriptions.您将找到所有错误及其响应代码的列表以及信息说明。 One thing is important tough: Stick to one format, otherwise it will be a pain for clients.有一点很重要:坚持一种格式,否则对客户来说会很痛苦。 Most APIs also only use about 6-8 HTTP response codes.大多数 API 也仅使用大约 6-8 个 HTTP 响应代码。

Also, Spring has a number of utilities to help you out:此外,Spring 有许多实用程序可以帮助您:

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

Or, the following annotation to create a custom response format:或者,使用以下注释创建自定义响应格式:

@ExceptionHandler({ YourException.class })

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM