首页 文章

Reactive WebClient不会发出响应

提问于
浏览
3

我有一个关于Spring Reactive WebClient的问题...几天前我决定使用Spring Framework中新的反应性东西,我做了一个小项目,只为个人目的抓取数据 . (向一个网页发出多个请求并合并结果) .

我开始使用新的反应式WebClient来发出请求但我发现的问题是客户端没有为每个请求发出响应 . 听起来很奇怪 . 以下是我为获取数据所做的工作:

private Mono<String> fetchData(String uri) {
    return this.client
            .get()
            .uri(uri)
            .header("X-Fsign","SW9D1eZo")
            .retrieve()
            .bodyToMono(String.class)
            .timeout(Duration.ofSeconds(35))
            .log("category", Level.ALL, SignalType.ON_ERROR, SignalType.ON_COMPLETE, SignalType.CANCEL, SignalType.REQUEST);
}

并调用 fetchData 的函数:

public Mono<List<Stat>> fetch() {
    return fetchData(URL)
            .map(this::extractUrls)
            .doOnNext(System.out::println)
            .doOnNext(s-> System.out.println("all ids are "+s.size()))
            .flatMapIterable(q->q)
            .map(s -> s.substring(7, 15))
            .map(s -> "http://d.flashscore.com/x/feed/d_hh_" + s + "_en_1") // list of N-length urls
            .flatMap(this::fetchData)
            .map(this::extractHeadToHead)
            .collectList();
}

和订户:

FlashScoreService bean = ctx.getBean(FlashScoreService.class);
    bean.fetch().subscribe(s->{
        System.out.println("finished !!! " + s.size()); //expecting same N-length list size
    },Throwable::printStackTrace);

问题是如果我做了更多的请求> 100.我没有得到所有这些的响应,没有抛出错误或返回错误响应代码并调用订阅方法,其大小与请求数量不同 .

我提出的请求是基于字符串列表(URL),在发出所有响应之后,我应该将所有响应作为列表接收,因为我正在使用 collectList() . 当我执行100个请求时,我希望收到100个响应的列表,但实际上我有时会收到100个,有时候会收到96个等等...可能是某些事情无声地失败了 . 这很容易重现,这是我的github项目link .

样本输出:

all ids are 176
finished !!! 171

请给我建议我如何调试或我做错了什么 . 感谢帮助 .

更新:

日志显示我是否传递了126个网址,例如:

onNext(ReactorClientHttpResponse{request=[GET/some_url],status=200}) is called 121 times. May be here is the problem.
onComplete() is called 126 times which is the exact same length of the passed list of urls

但是如果不调用onNext()或onError()就可以完成一些请求? (Mono的成功与错误)

我认为问题不在WebClient中,而在于其他地方 . 环境或服务器阻塞请求,但可能是我应该收到一些错误日志 .

PS . 谢谢您的帮助 !

1 回答

  • 2

    这是一个棘手的问题 . 调试收到的实际HTTP帧,似乎我们真的没有获得某些请求的响应 . 使用Wireshark进行一些调试,看起来远程服务器正在请求使用 FIN, ACK TCP数据包结束连接并且客户端确认它 . 问题是仍然从池中获取此连接以在第一个 FIN, ACK TCP数据包之后发送另一个GET请求 .

    也许远程服务器在服务了大量请求后正在关闭连接;无论如何,这是完全合法的行为 . 请注意,我不是一直在复制这个 .

    解决方法

    您可以在客户端上禁用连接池;这会慢一点,显然不会触发这个问题 . 为此,请使用以下内容:

    this.client = WebClient.builder()
                    .clientConnector(new ReactorClientHttpConnector(new Consumer<HttpClientOptions.Builder>() {
                        @Override
                        public void accept(HttpClientOptions.Builder builder) {
                            builder.disablePool();
                        }
                    }))
                    .build();
    

    基础问题

    根本问题是当TCP连接关闭而不发送响应时,HTTP客户端不应该 onComplete . 或者更好的是,当我知道更多信息时,HTTP客户端不应该重新使用连接,而_1293088会报告回来 .

相关问题