Spring 5 响应式(Reactive)异常处理

标签 spring exception-handling spring-webflux

我正在编写一个复杂的应用程序作为 Spring 5 Webflux 的实验。我打算在这个应用程序中使用很多技术。我熟悉“旧风格”@RestController,但现在,我正在编写功能端点。例如。公司注册服务的后端。我在“旧世界”中寻找类似@ControllerAdvice 的东西。但我真的无法找到任何类似于响应式(Reactive)等效物的东西。 (或者任何对我有用的东西。)

我有一个非常基本的设置。一个路由函数、一个响应式 Cassandra 存储库、一个处理程序和一个测试类。存储库操作可能会抛出 IllegalArgumentException,我想通过将 HTTP Status BadRequest 返回给客户端来处理它。只是作为我有能力做到这一点的一个例子。 :-) 异常由处理程序类处理。这是我的代码。

RouterConfig

@Slf4j
@Configuration
@EnableWebFlux
public class RouterConfig {

@Bean
public RouterFunction<ServerResponse> route(@Autowired CompanyHandler handler) {
    return RouterFunctions.route()
            .nest(path("/company"), bc -> bc
                    .GET("/{id}", handler::handleGetCompanyDataRequest)                     
                    .before(request -> {
                        log.info("Request={} has been received.", request.toString());
                        return request;
                    })
            .after((request, response) -> {
                log.info("Response={} has been sent.", response.toString());
                return response;
            }))
            .build();       
    }
}

公司经理
@Slf4j
@Component
public class CompanyHandler {

    @Autowired
    private ReactiveCompanyRepository repository;

    // Handle get single company data request
    public Mono<ServerResponse> handleGetCompanyDataRequest(ServerRequest request) {
        //Some validation ges here

        return repository.findById(Mono.just(uuid))
            .flatMap(this::ok)
            .onErrorResume(IllegalArgumentException.class, e -> ServerResponse.badRequest().build())
            .switchIfEmpty(ServerResponse.notFound().build());
    }

    private Mono<ServerResponse> ok (Company c) {
        return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON)
            .body(BodyInserters.fromPublisher(Mono.just(c), Company.class));
    }
}

ReactiveCompanyRepository
@Component
public interface ReactiveCompanyRepository extends ReactiveCassandraRepository<Company, UUID>{

    Mono<Company> findByName(String name);

    Mono<Company> findByEmail(String email);
}

我的问题是 .onErrorResume(IllegalArgumentException.class, e -> ServerResponse.badRequest().build()) 永远不会被调用,并且在测试用例中:
@SuppressWarnings("unchecked")
@Test
public void testGetCompanyExceptionDuringFind() {

    Mockito.when(repository.findById(Mockito.any(Mono.class))).thenThrow(new IllegalArgumentException("Hahaha"));       

    WebTestClient.bindToRouterFunction(routerConfig.route(companyHandler))
        .build()
        .get().uri("/company/2b851f10-356e-11e9-a847-0f89e1aa5554")
        .accept(MediaType.APPLICATION_JSON_UTF8)
        .exchange()
        .expectStatus().isBadRequest()
        .returnResult(Company.class)
        .getResponseBody();
}

我总是得到 HttpStatus 500 而不是 400。所以它失败了。任何帮助将不胜感激!

最佳答案

您的测试并不代表响应式(Reactive) API 的行为方式。如果这样的存储库直接抛出异常,我会认为这是一个向维护者报告的错误。

当响应式(Reactive) API 返回类似 Mono 的响应式(Reactive)类型时或 Flux ,预计所有错误都不会直接抛出,而是在 react 管道中作为消息实际发送。

在这种情况下,您的测试用例应该更像是:

Mockito.when(repository.findById(Mockito.any(Mono.class)))
   .thenReturn(Mono.error(new IllegalArgumentException("Hahaha")));

有了这个,onError... Reactor 中的操作符将处理这些错误消息。

关于Spring 5 响应式(Reactive)异常处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54843870/

相关文章:

powershell - 在 Powershell 中应该使用什么异常类型来捕获由于无效字符引起的 XML 解析错误?

c# - .NET 中的 SOAP 请求

exception-handling - PyQt 事件处理程序 snarf 异常

java - 如何在 java 中使用构造函数基初始化来初始化 WebClient?

java - 在@bean 工厂方法上使用自定义注解

java - 确定正确的 Spring Boot 启动器

javascript - 在 JavaScript 中访问请求参数

java - 无法使用注释从 .properties 文件中提取值

java - 实现不带斜杠的 url

java - Spring Boot Webflux - flatMap 是链接 http 调用的正确方法吗?