How to Return 404 with Spring WebFlux – 如何用Spring WebFlux返回404

最后修改: 2019年 3月 15日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

With Spring Boot 2 and the new non-blocking server Netty, we don’t have the Servlet context API anymore, so let’s discuss the way how we can express different kind of HTTP status codes, using the new stack.

在Spring Boot 2和新的非阻塞服务器Netty中,我们不再有Servlet上下文API,所以让我们讨论如何使用新的栈来表达不同的HTTP状态代码。

2. Semantic Response Status

2.语义响应状态

Follow standard RESTful practice, we naturally need to make use of the full range of HTTP status codes to express the semantics of the API properly.

遵循标准的RESTful实践,我们自然需要利用全部的HTTP状态代码来正确表达API的语义。

2.1. Default Return Status

2.1.默认返回状态

Of course, when everything goes well, the default response status is the 200 (OK):

当然,当一切顺利的时候,默认的响应状态是200(OK)

@GetMapping(
  value = "/ok",
  produces = MediaType.APPLICATION_JSON_UTF8_VALUE
)
public Flux<String> ok() {
    return Flux.just("ok");
}

2.2. Using Annotations

2.2.使用注解

We can alter the default return status adding the @ResponseStatus annotation to the method:

我们可以改变默认的返回状态,向方法添加@ResponseStatus注解。

@GetMapping(
  value = "/no-content",
  produces = MediaType.APPLICATION_JSON_UTF8_VALUE
)
@ResponseStatus(HttpStatus.NO_CONTENT)
public Flux<String> noContent() {
    return Flux.empty();
}

2.3. Changing the Status Programmatically

2.3.以编程方式改变状态

In some cases, depending on our server’s behavior, we could decide to change the returned status programmatically instead of a prefixed returned status used by default or with annotations.

在某些情况下,根据我们服务器的行为,我们可以决定以编程方式改变返回的状态,而不是默认使用的或带有注释的前缀的返回状态。

We can achieve that injecting ServerHttpResponse in our method directly:

我们可以直接在我们的方法中注入ServerHttpResponse来实现。

@GetMapping(
  value = "/accepted",
  produces = MediaType.APPLICATION_JSON_UTF8_VALUE
)
public Flux<String> accepted(ServerHttpResponse response) {
    response.setStatusCode(HttpStatus.ACCEPTED);
    return Flux.just("accepted");
}

Now we can choose which HTTP status code we return right in the implementation.

现在我们可以在实现中选择返回哪个HTTP状态代码。

2.4. Throwing an Exception

2.4.抛出一个异常

Any time we throw an exception, the default HTTP return status is omitted and Spring tries to find an exception handler to deal with it:

任何时候我们抛出一个异常,默认的HTTP返回状态就会被省略,Spring会试图找到一个异常处理程序来处理它。

@GetMapping(
  value = "/bad-request"
)
public Mono<String> badRequest() {
    return Mono.error(new IllegalArgumentException());
}
@ResponseStatus(
  value = HttpStatus.BAD_REQUEST,
  reason = "Illegal arguments")
@ExceptionHandler(IllegalArgumentException.class)
public void illegalArgumentHandler() {
    // 
}

To learn more about how to do that, definitely check-out the Error Handling article on Baeldung.

要了解更多关于如何做到这一点,一定要看看Baeldung上的错误处理文章

2.5. With ResponseEntity

2.5.使用ResponseEntity

Let’s now have a quick look at an interesting alternative – the ResponseEntity class.

现在让我们快速浏览一下一个有趣的替代方案–ResponseEntity类。

This allows us to choose which HTTP status we want to return and also to customize our responses much further, using a very useful fluent API:

这使得我们可以选择我们想要返回的HTTP状态,也可以使用一个非常有用的流畅的API来进一步定制我们的响应。

@GetMapping(
  value = "/unauthorized"
)
public ResponseEntity<Mono<String>> unathorized() {
    return ResponseEntity
      .status(HttpStatus.UNAUTHORIZED)
      .header("X-Reason", "user-invalid")
      .body(Mono.just("unauthorized"));
}

2.6. With Functionals Endpoints

2.6.带有函数的端点

With Spring 5, we can define endpoints in a functional way, so, we can change the default HTTP status programmatically as well:

在Spring 5中,我们可以用功能化的方式来定义端点,因此,我们也可以通过编程方式来改变默认的HTTP状态。

@Bean
public RouterFunction<ServerResponse> notFound() {
    return RouterFunctions
      .route(GET("/statuses/not-found"),
         request -> ServerResponse.notFound().build());
}

3. Conclusion

3.总结

When implementing an HTTP API, the framework gives a number of options to intelligently deal with the status codes we’re exposing back to the client.

在实现HTTP API时,该框架提供了许多选项来智能地处理我们暴露给客户端的状态代码。

This article should be a good starting point to explore these and understand how you can roll out expressive, friendly API, with clean, RESTful semantics.

这篇文章应该是一个很好的起点,可以探索这些问题,并了解你如何能够推出具有简洁、RESTful语义的表达式、友好的API。

Of course, the complete code examples used in this tutorial are available over on Github.

当然,本教程中所使用的完整代码示例可在Github上获得