gpt4 book ai didi

spring - 响应式(Reactive) WebClient 不发出响应

转载 作者:行者123 更新时间:2023-12-04 08:47:37 24 4
gpt4 key购买 nike

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

我开始使用新的响应式(Reactive) 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。
我没有得到所有响应,没有抛出错误或返回错误响应代码,并且调用 subscribe 方法的大小与请求数不同。

我提出的请求基于字符串列表(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 中,而在其他地方。环境或服务器阻塞了请求,但可能我应该收到一些错误日志。

附:谢谢您的帮助 !

最佳答案

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

也许远程服务器在处理了大量请求后关闭了连接;无论如何,这是完全合法的行为。请注意,我并没有始终如一地重现这一点。

解决方法

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

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

根本问题

根本问题是HTTP客户端不应该 onComplete当 TCP 连接关闭而不发送响应时。或者更好的是,HTTP 客户端在关闭时不应重用连接。当我知道更多时,我会在这里报告。

关于spring - 响应式(Reactive) WebClient 不发出响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44930448/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com