Spring Webflux webclient 出现问题,尝试发送发布请求时没有任何反应

Posted

技术标签:

【中文标题】Spring Webflux webclient 出现问题,尝试发送发布请求时没有任何反应【英文标题】:Issue with Spring Webflux webclient , nothing happens when trying to send post request 【发布时间】:2019-10-12 08:49:18 【问题描述】:

有以下webclient的实现:

    public <T> WebClient.ResponseSpec sendRequest(HttpMethod method, String contentType, T body, String baseUrl, String path) 
    try 
        WebClient webClient = WebClient.builder().baseUrl(baseUrl).filter(logRequest()).build();
        WebClient.ResponseSpec responseSpec = webClient.method(method)
                .uri(path)
                .header(HttpHeaders.CONTENT_TYPE, contentType)
                .body(BodyInserters.fromObject(body))
                .retrieve();
        return responseSpec;
     catch (Exception e) 
        throw new WebClientProcessingException("Exception when trying to execute request", e);

    


// This method returns filter function which will log request data
private static ExchangeFilterFunction logRequest() 
    return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> 
        LOGGER.info("Request:   ", clientRequest.method(), clientRequest.url(), clientRequest.body());
        clientRequest.headers().forEach((name, values) -> values.forEach(value -> LOGGER.info("=", name, value)));
        return Mono.just(clientRequest);
    );

还有如下代码,创建用户对象和包含用户对象的命令,然后调用webclient发送请求

@Autowired
private BaseWebClient baseWebClient;
@Override
public void saveOrUpdateUser() 
        UserPayload userPayload = new UserPayload();
        userPayload.setUserId(111L);
        userPayload.setCreatedAt(ZonedDateTime.now(DateTimeProps.systemTimeZone));
        UserCommand userCommand = new UserCommand();
        userCommand.setUser(userPayload);
        baseWebClient.sendRequest(HttpMethod.POST, "application/json",
            Stream.of(userCommand).collect(Collectors.toList()),
            "http://localhost:8080",
            "/users").onStatus(HttpStatus::isError, clientResponse -> 
        throw new WebClientUserSaveOrUpdateeFailedException("Exception when trying to update user state")
        .bodyToMono(String.class);
    );

用户负载:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserPayload 
  Long userId;
  ZonedDateTime createdAt;

用户命令:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserCommand 
     @JsonProperty("user")
     UserPayload user;

Json 正在等待我的其他应用程序(我正在发送请求):

[
   "user":
             
              "userId": 1,
              "createdAt": "2019-05-16T08:24:46.412Z"
             
  
]

使用:Spring boot 2、Lombok(用于 getter/setter)、gradle 当我尝试发送请求时,什么也没有发生。甚至没有例外。 我尝试了非常简单的案例以及同样的问题。 还有一点,是否可以记录正文?我的意思是以某种方式看到最终的 json 我想我缺少一般的东西。

【问题讨论】:

【参考方案1】:

在反应堆中,nothing happens until you subscribe。 retrive() 实际上并没有启动请求。正如您在example 中看到的那样,您应该使用其中一种方法将 ResponseSpec 转换为发布者,然后最终订阅该发布者。

根据您使用此方法的方式,您也许可以让 Spring 订阅发布者。 WebFlux 支持模型中的响应式类型,这意味着您可以通过 RestController 方法 directly return a Mono,例如。

【讨论】:

是的,你是对的,但我使用的是 .bodyToMono(String.class); ,抱歉问题也更新了。据我所知,不需要其他任何东西,对吧?或者我错过了什么? 即使这样做,也没有人订阅 Mono。您需要自己调用 subscribe() 或 block(),或者将 Mono 交给 Spring 处理。 我最终来到这里是因为同样的问题我设法通过以下方式摆脱了:1)调用block(),只是为了检查,因为我不希望我的客户端阻塞线程,并且它有效; 2) 然后我明确订阅了我的 post() 返回的 Mono,它再次起作用。我怀疑这个显式的订阅调用通常被 Spring 隐藏,或者用@Panda 的话说“将 Mono 交给 Spring 处理”,但我还没有找到任何方法来摆脱订阅调用。有谁知道在调用 exchangeToMono/bodyToMono 之后发布者和订阅者如何最终绑定在一起? ... 以便最终可以释放请求。此外,我猜在应用程序代码中调用 subscribe() 会使应用程序负责通过调用 dispose() 释放订阅,否则内存将泄漏。

以上是关于Spring Webflux webclient 出现问题,尝试发送发布请求时没有任何反应的主要内容,如果未能解决你的问题,请参考以下文章

Spring WebFlux WebClient 弹性和性能

Spring 5 webflux如何在Webclient上设置超时

在 Spring WebFlux webclient 中设置超时

Spring Webflux WebClient

如何模拟 Spring WebFlux WebClient?

如何在 Spring 5 WebFlux WebClient 中设置超时