Spring 5 反应式异常处理
Spring 5 reactive exception handling
我正在编写一个复杂的应用程序作为 Spring 5 Webflux 的实验。我打算在此应用程序中使用很多技术。我熟悉 "old style" @RestController,但现在,我正在编写功能端点。例如。公司注册的后端 service.I 是在 "old world" 中的 @ControllerAdvice 之后。但我真的无法找到任何与反应等效物相似的东西。 (或任何对我有用的东西。)
我有一个非常基本的设置。路由功能、反应式 Cassandra 存储库、处理程序和测试 class。存储库操作可以抛出 IllegalArgumentException,我想通过将 HTTP Status BadRequest 返回给客户端来处理它。举个例子,我有能力做到。 :-) 异常由处理程序 class 处理。这是我的代码。
路由器配置
@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。所以它 fails.Any 帮助将不胜感激!
您的测试不代表响应式 API 的行为方式。如果这样的存储库直接抛出异常,我会认为这是一个错误报告给维护者。
当反应式 API returns 像 Mono
或 Flux
这样的反应式类型时,预计所有错误都不会直接抛出,但实际上会作为消息发送反应管道。
在这种情况下,您的测试用例应该更像是:
Mockito.when(repository.findById(Mockito.any(Mono.class)))
.thenReturn(Mono.error(new IllegalArgumentException("Hahaha")));
这样,
onError...
Reactor 中的运算符将处理这些错误消息。
我正在编写一个复杂的应用程序作为 Spring 5 Webflux 的实验。我打算在此应用程序中使用很多技术。我熟悉 "old style" @RestController,但现在,我正在编写功能端点。例如。公司注册的后端 service.I 是在 "old world" 中的 @ControllerAdvice 之后。但我真的无法找到任何与反应等效物相似的东西。 (或任何对我有用的东西。)
我有一个非常基本的设置。路由功能、反应式 Cassandra 存储库、处理程序和测试 class。存储库操作可以抛出 IllegalArgumentException,我想通过将 HTTP Status BadRequest 返回给客户端来处理它。举个例子,我有能力做到。 :-) 异常由处理程序 class 处理。这是我的代码。
路由器配置
@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。所以它 fails.Any 帮助将不胜感激!
您的测试不代表响应式 API 的行为方式。如果这样的存储库直接抛出异常,我会认为这是一个错误报告给维护者。
当反应式 API returns 像 Mono
或 Flux
这样的反应式类型时,预计所有错误都不会直接抛出,但实际上会作为消息发送反应管道。
在这种情况下,您的测试用例应该更像是:
Mockito.when(repository.findById(Mockito.any(Mono.class)))
.thenReturn(Mono.error(new IllegalArgumentException("Hahaha")));
这样,
onError...
Reactor 中的运算符将处理这些错误消息。