跳至主要內容

WebClient第一次请求返回 Connection reset by peer 的错误

DD编辑部原创Spring BootSpring Boot大约 2 分钟

WebClient第一次请求返回 Connection reset by peer 的错误

我有一个需求,需要从外部系统获取用户数据。我通过 WebClient 实现的,作为声明性 HTTP 客户端的一部分。

有趣的是,在新的浏览器标签页中打开应用程序后,第一次请求返回了“Connection reset by peer”错误。

这个问题通过禁用对外请求的 keep-alive 解决了。

改造前的代码:

@Configuration
public class HttpProxyConfiguration {

    @Value("${tracker.url}")
    private String trackerUrl;

    @Bean
    TrackerClient trackerClient(WebClient.Builder builder) {
        var wc = builder.baseUrl(trackerUrl)
                .build();

        var wca = WebClientAdapter.forClient(wc);
        return HttpServiceProxyFactory.builder()
                .clientAdapter(wca)
                .build()
                .createClient(TrackerClient.class);
    }
}

改造后的代码:

@Configuration
public class HttpProxyConfiguration {

    @Value("${tracker.url}")
    private String trackerUrl;

    @Bean
    TrackerClient trackerClient(WebClient.Builder builder) {
        var httpClient = HttpClient.newConnection().keepAlive(false);
        var reactorClientHttpConnector = new ReactorClientHttpConnector(httpClient);

        var wc = builder.baseUrl(trackerUrl)
                .clientConnector(reactorClientHttpConnector)
                .build();

        var wca = WebClientAdapter.forClient(wc);
        return HttpServiceProxyFactory.builder()
                .clientAdapter(wca)
                .build()
                .createClient(TrackerClient.class);
    }

在查看了这个 GitHub Issue (https://github.com/reactor/reactor-netty/issues/388#issuecomment-704069492)后,似乎禁用连接池或禁用 keep-alive 并不推荐。

因此,我采用了该 GitHub Issue (https://github.com/reactor/reactor-netty/issues/1774#issuecomment-908066283)中提到的解决方案,设置了某些连接超时。

@Configuration
public class HttpProxyConfiguration {

    @Value("${tracker.url}")
    private String trackerUrl;

    @Bean
    TrackerClient trackerClient(WebClient.Builder builder) {
        ConnectionProvider provider = ConnectionProvider.builder("fixed")
                .maxConnections(500)
                .maxIdleTime(Duration.ofSeconds(20))
                .maxLifeTime(Duration.ofSeconds(60))
                .pendingAcquireTimeout(Duration.ofSeconds(60))
                .evictInBackground(Duration.ofSeconds(120)).build();

        HttpClient httpClient = HttpClient.create(provider);
        httpClient.warmup().block();

        var reactorClientHttpConnector = new ReactorClientHttpConnector(httpClient);

        var wc = builder.baseUrl(trackerUrl)
                .clientConnector(reactorClientHttpConnector)
                .build();

        var wca = WebClientAdapter.forClient(wc);
        return HttpServiceProxyFactory.builder()
                .clientAdapter(wca)
                .build()
                .createClient(TrackerClient.class);
    }
}

上述代码已经至少在生产环境中运行了两周。到目前为止,我还没有遇到任何错误。通过设置连接池,我希望能够提高应用程序的性能,特别是由于它经常需要向另一个服务发出大量请求以获取前端所需的所有数据。我计划继续长期监控这个解决方案,以评估其影响,并确定它是否确实提升了应用程序的性能。

本文翻译自原文:https://medium.com/@jskim1991/spring-boot-how-to-solve-webclient-connection-reset-by-peer-error-b1fa38e4106a

上次编辑于:
贡献者: 程序猿DD