当前位置: 首页 > 知识库问答 >
问题:

Spring webclient未记录错误响应并在收到错误时执行使用者操作

暴阳州
2023-03-14

我有一个Spring引导服务,其中API通过RouterFunction公开。一旦收到API请求,就会触发某些验证。其中一个验证,通过网络客户端调用另一个应用编程接口来验证接收到的值是否存在。如果value不存在,则必须记录错误消息并将错误消息添加到数组列表中。

但是,下面的实现既不记录错误也不记录成功消息,也无法在数组列表中添加错误消息。

我也试图使用块(),但这给了

'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())));

                });
    }
}

正在调用另一个API以验证值的Webclient

@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
    }   
}

共有1个答案

何乐
2023-03-14

此方法返回一个未被任何人订阅的Mono。此代码在隔离状态下不执行任何操作。

identityApiClient.retrieveIdentityDetail(identityLocal)
                            .doOnError(e -> errorDetailConsumer.accept(new ErrorDetail(REQUEST_INVALID_PARAM, e.getMessage())));

反应式编程的咒语是

“在您订阅之前不会发生任何事情”

对于大多数用例,基础框架(在本例中为Spring)将为您订阅Mono,只要您从您的RouterFunction返回它。

我不完全熟悉您的需求,但一个可能的解决方案是重构您的验证器,使其具有反应性,并将其添加到您的反应性流中。

 类似资料:
  • 0.3 新版功能. 应用故障,服务器故障。早晚你会在产品中看见异常。即使你的代码是 100% 正确的, 你仍然会不时看见异常。为什么?因为涉及的所有一切都会出现故障。这里给出一些 完美正确的代码导致服务器错误的情况: 客户端在应用读取到达数据时,提前终止请求 数据库服务器超载,并无法处理查询 文件系统满了 硬盘损坏 后端服务器超载 你所用的库出现程序错误 服务器的网络连接或其它系统故障 而且这只是

  • 问题内容: 我在ubuntu上使用npm v1.0.104 / node 0.6.12-在尝试通过npm安装任何新模块时收到以下复制的错误(我之前使用http而不是https测试了socket.io,但我想知道是否可以导致npm / unsigned证书出现问题)。一旦npm尝试解析“ https://registry.npmjs.org ” URL,该错误就会弹出。无论如何,我可以忽略该错误,或

  • 失败:生成失败,出现异常。 > 其中:脚本'C:\src\flutter\包\flutter_tools\gradle\flutter.gradle'行:1035 错误:任务:app:compileFlutterBuildDebug的执行失败。 进程'命令'C:\src\flutter\bin\flutter.bat"以非零退出值1结束 尝试:使用--stack-trace选项运行以获取堆栈跟踪。

  • 我正在学习Fastapi,我正在localhost启动一个uvicorn服务器。每当出现错误/异常时,我都不会得到回溯。所有我得到的是: 所以,调试很困难,我正在试用python的日志模块 我还尝试过使用调试参数启动uvicorn

  • 以下是该应用程序的权限。它将读取和写入图像文件到外部存储,以及使用相机拍摄照片。该应用程序不访问其他资源,如联系人,短信和日历。 android.permission.access_network_state android.permission.camera android.permission.internet android.permission.read_external_storage

  • 在这里输入图片描述 其他人说「androidx.core:core-ktx:」是问题所在,但我找不到对这个库的依赖