webflux客户端发请求处理响应时遇到的

研究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)

搜索后得出初步结论:

  1. netty的线程不允许阻塞,因为是在netty的pipeline里,而netty的线程本身是不允许阻塞的。我自己虽然用过netty多次,确实没有遇到过需要阻塞它的onRead线程,虽然没试过是不是真的netty线程不允许阻塞,但想必是没有这样用的情景。
  2. 不要在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();
    }

你可能感兴趣的:(webflux)