WebClient 上的阻止调用无限期挂起
Blocking calls on WebClient hangs indefinitely
我有三个 WebClient,看起来像这样:
WebClient
public Mono<MyObject> getResponseOne() {
return webClient.get()
.uri(URI)
.header("header", header)
.bodyValue(body)
.retrieve()
.bodyToMono(MyObject.class);
}
然后我有一个调用多个 WebClient 的控制器:
控制器
@ResponseBody
@PostMapping("/get")
public Mono<MyObject> processResponse() {
MyObject obj = getResponseOne().toFuture().get();
system.out.println("Got first response");
String str = getResponseTwo().toFuture().get();
system.out.println("Got second response");
//process and send with third WebClient
MyObject newObj = getResponseThree(obj, str).toFuture().get();
//process response from third WebClient and send to fourth WebClient
//return statement
}
当我调用 /get
时,控制台只打印 "Got first response"
然后就停在那里,下面的任何内容似乎都没有执行。我正在使用 Postman 发送请求,所以它一直在等待而没有得到任何响应。
这可能相关也可能不相关,但我正在使用阻塞调用,因为我需要在将其发送到第三个 WebClient 之前处理两个响应,来自第三个 WebClient 的响应也将在之前进行额外处理作为 processResponse()
.
的响应返回
解决方案
我按照亚历克斯的建议使用了 Mono.zip()
:
@ResponseBody
@PostMapping("/get")
public Mono<MyObject> processResponse() {
//TupleN depends on the amount of Monos you want to process
Mono<Tuple2<MyObject,String>> output = Mono.zip(getResponseOne(),getResponseTwo());
return output.map(result ->{
// getT1() & getT2() is automatically generated by the tuple
MyObject obj = result.getT1();
String str = result.getT2();
getResponseThree(obj, str);
//process and return
});
}
更多关于Mono.zip()
反应式 API 在您订阅之前什么都不会发生。您的方法 returns Mono
并且您需要构建一个流合并发布者。根据需要的逻辑,有多种组合方式。
例如,如果您需要前任的结果,您可以使用 flatMap
依次解析 Mono
return getResponseOne()
.flatMap(res -> getResponseTwo(res))
.flatMap(res -> getResponseThree(res));
如果调用是独立的,您可以使用 then
return getResponseOne()
.then(getResponseTwo())
.then(getResponseThree());
您也可以使用 Mono.when(getResponseOne(), getResponseTwo(), getResponseThree())
或 Mono.zip(getResponseOne(), getResponseTwo(), getResponseThree())
.
并行执行
还有许多其他运算符,但这里的关键是构建流和 return Mono
或 Flux
.
我有三个 WebClient,看起来像这样:
WebClient
public Mono<MyObject> getResponseOne() {
return webClient.get()
.uri(URI)
.header("header", header)
.bodyValue(body)
.retrieve()
.bodyToMono(MyObject.class);
}
然后我有一个调用多个 WebClient 的控制器:
控制器
@ResponseBody
@PostMapping("/get")
public Mono<MyObject> processResponse() {
MyObject obj = getResponseOne().toFuture().get();
system.out.println("Got first response");
String str = getResponseTwo().toFuture().get();
system.out.println("Got second response");
//process and send with third WebClient
MyObject newObj = getResponseThree(obj, str).toFuture().get();
//process response from third WebClient and send to fourth WebClient
//return statement
}
当我调用 /get
时,控制台只打印 "Got first response"
然后就停在那里,下面的任何内容似乎都没有执行。我正在使用 Postman 发送请求,所以它一直在等待而没有得到任何响应。
这可能相关也可能不相关,但我正在使用阻塞调用,因为我需要在将其发送到第三个 WebClient 之前处理两个响应,来自第三个 WebClient 的响应也将在之前进行额外处理作为 processResponse()
.
解决方案
我按照亚历克斯的建议使用了 Mono.zip()
:
@ResponseBody
@PostMapping("/get")
public Mono<MyObject> processResponse() {
//TupleN depends on the amount of Monos you want to process
Mono<Tuple2<MyObject,String>> output = Mono.zip(getResponseOne(),getResponseTwo());
return output.map(result ->{
// getT1() & getT2() is automatically generated by the tuple
MyObject obj = result.getT1();
String str = result.getT2();
getResponseThree(obj, str);
//process and return
});
}
更多关于Mono.zip()
反应式 API 在您订阅之前什么都不会发生。您的方法 returns Mono
并且您需要构建一个流合并发布者。根据需要的逻辑,有多种组合方式。
例如,如果您需要前任的结果,您可以使用 flatMap
依次解析 Mono
return getResponseOne()
.flatMap(res -> getResponseTwo(res))
.flatMap(res -> getResponseThree(res));
如果调用是独立的,您可以使用 then
return getResponseOne()
.then(getResponseTwo())
.then(getResponseThree());
您也可以使用 Mono.when(getResponseOne(), getResponseTwo(), getResponseThree())
或 Mono.zip(getResponseOne(), getResponseTwo(), getResponseThree())
.
还有许多其他运算符,但这里的关键是构建流和 return Mono
或 Flux
.