【发布时间】:2026-02-18 02:45:02
【问题描述】:
我有一个 Spring Boot 服务,其中 API 通过 RouterFunction 公开。一旦收到 API 请求,就会触发某些验证。其中一个验证,通过 webclient 调用另一个 API 来验证接收到的值是否存在。如果 value 不存在,则必须记录错误消息并将错误消息添加到数组列表中。
但是,下面的实现既不记录错误也不记录成功消息,也不能在数组列表中添加错误消息。
我也尝试使用 block() 但这给出了
'IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-epoll-3'
如果我通过 RouterFunction 直接公开一个 API 只是为了调用该查找 API,那么一切正常。这表明通过验证层进行调用会导致问题,可能是同步和反应式调用方式存在问题。
我无法理解我的实现问题。请指导我做错了什么。
触发外部验证的验证类
@Slf4j
@Component
@RequiredArgsConstructor
public class EmployeeValidation{
private final IdentityApiClient identityApiClient;
public List<ErrorDetail> validate(Optional<EmployeeRequestDto> employeeRequest) {
var errors = new ArrayList<ErrorDetail>();
employeeRequest
.ifPresent(employee -> {
//some other validations
if (errors.isEmpty()) {
validateIfIdentityExist(employee.getSecuredEmployeeDetail(), errors::add);
}
});
return errors;
}
private void validateIfIdentityExist(SecuredEmployeeDetailDto securedEmployeeDetailDto, Consumer<ErrorDetail> errorDetailConsumer) {
Optional.ofNullable(securedEmployeeDetailDto)
.map(SecuredEmployeeDetailDto::getIdentity)
.ifPresent(identityLocal -> {
log.info("Going to retrieve identity [{}] detail", identityLocal);
identityApiClient.retrieveIdentityDetail(identityLocal)
.doOnError(e -> errorDetailConsumer.accept(new ErrorDetail(REQUEST_INVALID_PARAM, e.getMessage())));
});
}
}
Webclient 正在调用另一个 API 来验证值
@Slf4j
@Component
@RequiredArgsConstructor
public class IdentityApiClient {
private final WebClient identityWebClient;
private final IdentityProperties identityProperties;
public Mono<IdentityDetail> retrieveIdentityDetail(String identity) {
log.info("Going to retrieve identity [{}] detail", identity);
return identityWebClient
.get()
.uri(identityProperties.getLookupPath(), Map.of("identity", identity))
.retrieve()
.onStatus(httpStatus -> httpStatus.equals(UNAUTHORIZED),
clientResponse -> clientResponse.bodyToMono(String.class)
.flatMap(identityLookUpErrorResponse -> Mono.error(new IdentityLookUpException(UNAUTHORIZED.value(), IdentityLookUpErrorResponse.builder()
.error(identityLookUpErrorResponse)
.message("Unauthorized Access")
.status(UNAUTHORIZED.value())
.build()))))
.onStatus(HttpStatus::is4xxClientError,
clientResponse -> clientResponse.bodyToMono(IdentityLookUpErrorResponse.class)
.switchIfEmpty(Mono.just(IdentityLookUpErrorResponse.builder()
.error("Received Empty Response Body")
.message("Unknown Identity")
.status(NOT_FOUND.value())
.build()))
.flatMap(identityLookUpErrorResponse -> Mono.error(new IdentityLookUpException(identityLookUpErrorResponse.getStatus(), identityLookUpErrorResponse))))
.onStatus(HttpStatus::is5xxServerError,
clientResponse -> clientResponse.bodyToMono(IdentityLookUpErrorResponse.class)
.switchIfEmpty(Mono.just(IdentityLookUpErrorResponse.builder()
.error("Received Empty Response Body")
.message(INTERNAL_SERVER_ERROR.getReasonPhrase())
.status(INTERNAL_SERVER_ERROR.value())
.build()))
.flatMap(identityLookUpErrorResponse -> Mono.error(new IdentityLookUpException(identityLookUpErrorResponse.getStatus(), identityLookUpErrorResponse))))
.bodyToMono(IdentityDetail.class)
.doOnNext(response -> log.info("Identity [{}] response received", response)) // not getting logged when called via validator class
.doOnError(e -> log.error("Identity [{}] error response received", identity, e));// not getting logged when called via validator class
}
}
【问题讨论】:
-
使用您最喜欢的 IDE,尝试深入调试模式以准确了解逐行发生的情况。此外,您在 EmployeeValidation 和 IdentityApiClient 类之间构建了一个高耦合代码。如果可能,请检查并重新设计。
标签: java spring-boot spring-webflux spring-webclient