Nik*_*sev 8 spring reactive-programming project-reactor spring-webflux
我有一个关于Spring Reactive WebClient的问题...几天前,我决定使用Spring Framework中的新的React东西,并且我做了一个小项目,仅出于个人目的抓取数据。(对一个网页发出多个请求并合并结果)。
我开始使用新的反应式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);
}
Run Code Online (Sandbox Code Playgroud)
和调用的函数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();
}
Run Code Online (Sandbox Code Playgroud)
和订户:
FlashScoreService bean = ctx.getBean(FlashScoreService.class);
bean.fetch().subscribe(s->{
System.out.println("finished !!! " + s.size()); //expecting same N-length list size
},Throwable::printStackTrace);
Run Code Online (Sandbox Code Playgroud)
问题是如果我发出的请求多于100个,那么我没有得到所有响应,没有错误抛出,或者返回了错误响应代码,并以与请求数量不同的大小调用了subscription方法。
我提出的请求基于字符串列表(url),并且在发出所有响应之后,我应该将所有请求作为列表接收,因为我正在使用collectList()。当我执行100个请求时,我希望收到100个响应的列表,但实际上我有时会收到100,有时是96等。这很容易复制,这是我的github项目链接。
样本输出:
all ids are 176
finished !!! 171
Run Code Online (Sandbox Code Playgroud)
请给我建议如何调试或做错了什么。感谢帮助。
更新:
日志显示例如我是否传递了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
Run Code Online (Sandbox Code Playgroud)
但是,如何在不调用onNext()或onError()的情况下完成某些请求呢?(单声道中的成功和错误)
我认为问题不在WebClient中,而在其他地方。环境或服务器阻止了该请求,但可能是我应该收到一些错误日志。
ps。谢谢您的帮助 !
这是一个棘手的问题。调试收到的实际 HTTP 帧,似乎我们真的没有收到对某些请求的响应。使用 Wireshark 进行更多调试,看起来远程服务器正在请求使用FIN, ACKTCP 数据包结束连接,并且客户端已确认。问题是这个连接在第一个FIN, ACKTCP 数据包之后仍然从池中取出来发送另一个 GET 请求。
也许远程服务器在处理了大量请求后关闭了连接;无论如何,这是完全合法的行为。请注意,我并没有始终如一地重现这一点。
您可以在客户端禁用连接池;这会更慢,显然不会触发这个问题。为此,请使用以下内容:
this.client = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(new Consumer<HttpClientOptions.Builder>() {
@Override
public void accept(HttpClientOptions.Builder builder) {
builder.disablePool();
}
}))
.build();
Run Code Online (Sandbox Code Playgroud)
根本问题是,HTTP 客户端不应该onComplete在 TCP 连接关闭时不发送响应。或者更好的是,HTTP 客户端在关闭时不应重用连接。当我知道更多时,我会在这里报告。
| 归档时间: |
|
| 查看次数: |
4741 次 |
| 最近记录: |