【发布时间】:2021-11-29 19:43:20
【问题描述】:
[UPDATE 2021-10-11] 添加了 MCVE
https://github.com/SalathielGenese/issue-spring-webflux-reactive-error-advice
出于可重用性的考虑,我在服务层运行验证,返回Mono.error( constraintViolationException )...
这样我的 Web 处理程序只需将未编组的域转发到服务层。
到目前为止,非常棒。
但是我如何建议 (AOP) 我的 Web 处理程序,以便它返回带有格式化约束违规的 HTTP 422?
WebExchangeBindException 只处理同步抛出的异常(我不希望同步验证破坏响应式流程)。
我的 AOP 建议触发器和错误 b/c:
- 我的网络处理程序返回
Mono<DataType> - 但我的建议返回
ResponseEntity
如果我将我的响应实体(来自建议)包装成一个Mono<ResponseEntity>,我是一个HTTP 200 OK,响应实体序列化:(
代码摘录
@Aspect
@Component
class CoreWebAspect {
@Pointcut("withinApiCorePackage() && @annotation(org.springframework.web.bind.annotation.PostMapping)")
public void postMappingWebHandler() {
}
@Pointcut("within(project.package.prefix.*)")
public void withinApiCorePackage() {
}
@Around("postMappingWebHandler()")
public Object aroundWebHandler(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
try {
final var proceed = proceedingJoinPoint.proceed();
if (proceed instanceof Mono<?> mono) {
try {
return Mono.just(mono.toFuture().get());
} catch (ExecutionException exception) {
if (exception.getCause() instanceof ConstraintViolationException constraintViolationException) {
return Mono.just(getResponseEntity(constraintViolationException));
}
throw exception.getCause();
}
}
return proceed;
} catch (ConstraintViolationException constraintViolationException) {
return getResponseEntity(constraintViolationException);
}
}
private ResponseEntity<Set<Violation>> getResponseEntity(final ConstraintViolationException constraintViolationException) {
final var violations = constraintViolationException.getConstraintViolations().stream().map(violation -> new Violation(
stream(violation.getPropertyPath().spliterator(), false).map(Node::getName).collect(toList()),
violation.getMessageTemplate().replaceFirst("^\\{(.*)\\}$", "$1"))
).collect(Collectors.toSet());
return status(UNPROCESSABLE_ENTITY).body(violations);
}
@Getter
@AllArgsConstructor
private static class Violation {
private final List<String> path;
private final String template;
}
}
【问题讨论】:
-
我既不是响应式编程也不是 Spring 专家,只是 AOP 专家。但是,如果您在 GitHub 上有一个 MCVE我可以在最简单的设置中重现您的情况,我可以看看。我需要亲自看看到底发生了什么。
-
完成。谢谢@kriegaex
-
我查看了您的 MCVE 并且可以重现该问题。这看起来真的像一个反应式编程问题,我在这里没有深入了解,从来没有学过任何关于反应式编程的东西。但我相信 MCVE 能让一些反应型极客为您找到解决方案。
-
AOP 和反应式 PI 问题都不是……更多的是 Spring Webflux 实现问题。似乎它没有在节点的正确位置处理反应性错误。
-
嗯,我不能说什么聪明的话。但是如果你解决了你的问题,请写一个答案,以便回馈社区。谢谢。
标签: spring spring-boot spring-webflux project-reactor spring-aop