研究exchangeFunction和WebClient的用法时,无意踩到个坑,下面代码的exchangeFunctionWithResponse2,执行时异常:
java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-4
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:77)
at reactor.core.publisher.Mono.block(Mono.java:1494)
搜索后得出初步结论:
- netty的线程不允许阻塞,因为是在netty的pipeline里,而netty的线程本身是不允许阻塞的。我自己虽然用过netty多次,确实没有遇到过需要阻塞它的onRead线程,虽然没试过是不是真的netty线程不允许阻塞,但想必是没有这样用的情景。
- 不要在map或者flatMap的mapper或者transformer中使用block。这样会违背响应式的初衷,如果要使用block,使用restTemplate
public static void exchangeFunction() {
ExchangeFunction exchangeFunction = ExchangeFunctions.create(new ReactorClientHttpConnector());
ClientRequest request = ClientRequest
.create(HttpMethod.GET, URI.create("http://demo.com/basic-auth/user/passwd"))
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
.build();
exchangeFunctionWithString(request, exchangeFunction);
exchangeFunctionWithResponse(request, exchangeFunction);
exchangeFunctionWithResponse2(request, exchangeFunction);
}
private static void exchangeFunctionWithResponse(ClientRequest request, ExchangeFunction exchangeFunction) {
Mono<ClientResponse> exchange = exchangeFunction.exchange(request);
ClientResponse clientResponse = exchange.block();
String body = clientResponse.body(new MyBodyExtractor());
log.info("status code: {}, body: {}", clientResponse.statusCode(), body);
}
private static void exchangeFunctionWithResponse2(ClientRequest request, ExchangeFunction exchangeFunction) {
Mono<ClientResponse> exchange = exchangeFunction.exchange(request);
Mono<String> bodyMono = exchange
.map(clientResponse -> clientResponse.body(new MyBodyExtractor())); // block在map的mapper中会引起exception
log.info("body: {}", bodyMono.block());
}
static class MyBodyExtractor implements BodyExtractor<String, ReactiveHttpInputMessage> {
public String extract(ReactiveHttpInputMessage inputMessage, Context context) {
ParameterizedTypeReference<String> type = new ParameterizedTypeReference<String>() {};
BodyExtractor<Mono<String>, ReactiveHttpInputMessage> delegate = BodyExtractors.toMono(type);
return delegate
.extract(inputMessage, context)
.block();
}
}
// prints response message in string.
private static void exchangeFunctionWithString(ClientRequest request, ExchangeFunction exchangeFunction) {
Mono<String> result = exchangeFunction
.exchange(request)
.flatMap(clientResponse -> clientResponse.bodyToMono(String.class));
String block = result.block();
log.info("receive body: {}", block);
}
public static void main(String[] args) {
exchangeFunction();
}