Spring Boot WebClient的连接和读取超时。

5

目前我的Spring Boot项目中,使用WebClients处理post和get请求。WebClients具有通用的连接和读取超时时间。我有5个不同的类,每个类都需要自己的连接和读取超时时间。我不想创建5个不同的WebClients,而是想使用相同的WebClient,在从特定类发送post或者get请求时,指定所需的连接和读取超时时间。是否有实现这一要求的方法?

我的当前WebClient:

    @Bean
    public WebClient getWebClient(WebClient.Builder builder){

        HttpClient httpClient = HttpClient.newConnection()
                .tcpConfiguration(tcpClient -> {
                    tcpClient = tcpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectionTimeout*1000);
                    tcpClient = tcpClient.doOnConnected(conn -> conn
                            .addHandlerLast(new ReadTimeoutHandler(readTimeout, TimeUnit.SECONDS)));
                    return tcpClient;
                }).wiretap(true);

        ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);

        return builder.clientConnector(connector).build();
    }

我使用的是post请求:
public WebClientResponse httpPost(String endpoint, String requestData, Map<String, Object> requestHeader) {

        ClientResponse res = webClient.post().uri(endpoint)
                .body(BodyInserters.fromObject(requestData))
                .headers(x -> {
                    if(requestHeader != null && !requestHeader.isEmpty()) {
                        for (String s : requestHeader.keySet()) {
                            x.set(s, String.valueOf(requestHeader.get(s)));
                        }
                    }
                })
                .exchange()
                .doOnSuccess(x -> log.info("response code = " + x.statusCode()))
                .block();

        return convertWebClientResponse(res);
    }

您可以在WebClient中设置超时成员及其相应的setter方法。在发送每个请求之前,您可以使用setter更改超时值,然后调用适当的Get和Post请求。 - kiner_shah
3个回答

5
您可以在WebClient中配置请求级超时时间。
 webClient.get()
   .uri("https://baeldung.com/path")
   .httpRequest(httpRequest -> {
   HttpClientRequest reactorRequest = httpRequest.getNativeRequest();
   reactorRequest.responseTimeout(Duration.ofSeconds(2));
 });

现在你可以根据请求,从属性文件中添加这些值,或者将它们硬编码到代码中。参考链接:https://www.baeldung.com/spring-webflux-timeout

所以在 Duration.ofSeconds() 中,我传递了所需的超时时间。但是在我的配置中,我添加了 tcpClient 选项来设置连接和读取超时时间,我仍然不确定如何使用它来实现。 - Aditya K
这是您的默认超时时间。这将覆盖它们。 - Manish Kumar
是的,但我需要 TCP 级别的超时。这不是同一件事,对吧。 - Aditya K
它是一样的。该请求将使用提供的配置打开TCP连接。您还可以添加某种策略模式来修改此内容。 - Manish Kumar

0
@Bean
public WebClient getWebClient() {
    HttpClient httpClient = HttpClient.create()
            .tcpConfiguration(client ->
                    client.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 4000)
                            .doOnConnected(conn -> conn
                                    .addHandlerLast(new ReadTimeoutHandler(4)) 
                                    .addHandlerLast(new WriteTimeoutHandler(4))));
    ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient.wiretap(true));
    return WebClient.builder()
            .clientConnector(connector)
            .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) // if you need a default header
            .build();
}

或者您可以使用@Amol建议的方法


更改ReadTimeoutHandler和WriteTimeoutHandler的值不会改变读取/写入超时时间,其默认值为10秒。 - Roberto

0
您可以像下面这样使用 webClienttimeout 进行尝试。
webClient.post()
   .uri(..)
   .body(..)
   .retrieve()
   .
   .
   .
   .timeout(Duration.ofMillis(30);

30 只是一个例子。


3
这是由 Reactor 栈执行的超时,与 Spring WebClient 无关。它与 HTTP 请求的超时无关。 - Krzysztof Tomaszewski
1
感谢您的澄清,@KrzysztofTomaszewski。《Cloud Native Spring in Action》(Manning)第281页让它看起来这种设置会为GET请求本身设置超时。看起来这本书需要进行更正/澄清。不过当达到超时时间时,我想知道Reactor会做什么;它是否会以某种方式取消底层的HTTP请求? - Garret Wilson
我也很好奇。 - Krzysztof Tomaszewski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接