Я использую Web-flux / Reactive и Webclient, запустив его на tomcat и spring-boot.
Все нормально работает. Я много читал об этом. Проблема, похоже, заключается в том, что всякий раз, когда вы используете веб-клиент, вы должны возвращать или использовать ответ, иначе он закроет соединение, а вы его еще не использовали, и вы увидите много сообщений журнала, в которых говорится, что the connection close prematurely
, если я был сценарий, в котором код состояния 404 является ошибкой, я мог бы просто использовать OnStatus
и выбросить исключение, но мой сценарий таков: когда вышестоящая служба возвращает 404, я должен вручную вернуть пустое моно. поэтому я не использую ответ от запроса веб-клиента, я просто использую ClientResponse из .exchange (), чтобы проверить статус и обработать его. Моя первоначальная проблема - это сообщения журнала, потому что это просто «мусор», вы не хотите видеть много его в сообщениях журнала. Я где-то читал, что, если это произойдет, соединение также нельзя будет повторно использовать, поэтому это звучит очень плохо, но я не знаю ... и у меня просто это сообщение, когда оно не найдено, если ответ 200 он возвращает объект, и сообщения журнала не печатаются.
Я пытался использовать clientResponse.BodyToMono (Void.Class), но он тоже не работает. сообщения журнала продолжают появляться
@Bean
public WebClient webClient(
@Value("${http.client.connection-timeout-millis}") final int connectionTimeoutMillis,
@Value("${http.client.socket-timeout-millis}") final int socketTimeoutMillis,
@Value("${http.client.wire-tap-enabled}") final boolean wireTapEnabled,
final ObjectMapper objectMapper) {
Consumer<Connection> doOnConnectedConsumer = connection ->
connection
.addHandler(new ReadTimeoutHandler(socketTimeoutMillis, MILLISECONDS))
.addHandler(new WriteTimeoutHandler(connectionTimeoutMillis, MILLISECONDS));
TcpClient tcpClient = TcpClient.newConnection()
.wiretap(wireTapEnabled)
.option(CONNECT_TIMEOUT_MILLIS, connectionTimeoutMillis)
.doOnConnected(doOnConnectedConsumer);
return WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(HttpClient.from(tcpClient).compress(true)))
.exchangeStrategies(customExchangeStrategies(objectMapper))
.build();
}
// ..........
MultiValueMap<String, String> params = getParams(t1, t2);
return webClient.get()
.uri(HttpUtils.buildUrl(serviceUrl, params, name))
.exchange()
.flatMap(this::handleClientResponse)
.onErrorMap(Exception.class, ex -> handleUnexpectedEx(ex, name, params));
}
записи журнала
2019-07-08 11:56:51.972 WARN [-,,,] 1504 --- [ctor-http-nio-3] reactor.netty.channel.FluxReceive : [id: 0x66c8568c, L:/127.0.0.1:62319 ! R:localhost/127.0.0.1:8990] An exception has been observed post termination
reactor.netty.http.client.PrematureCloseException: Connection prematurely closed DURING response
2019-07-08 11:56:52.013 DEBUG [-,,,] 1504 --- [ctor-http-nio-2] reactor.netty.ReactorNetty : [id: 0xf50bdf8d, L:/127.0.0.1:62324 ! R:localhost/127.0.0.1:8990] Non Removed handler: ReadTimeoutHandler, context: ChannelHandlerContext(ReadTimeoutHandler, [id: 0xf50bdf8d, L:/127.0.0.1:62324 ! R:localhost/127.0.0.1:8990]), pipeline: DefaultChannelPipeline{(reactor.left.httpCodec = io.netty.handler.codec.http.HttpClientCodec), (reactor.left.decompressor = io.netty.handler.codec.http.HttpContentDecompressor), (WriteTimeoutHandler = io.netty.handler.timeout.WriteTimeoutHandler), (ReadTimeoutHandler = io.netty.handler.timeout.ReadTimeoutHandler), (reactor.right.reactiveBridge = reactor.netty.channel.ChannelOperationsHandler)}
2019-07-08 11:56:52.014 DEBUG [-,,,] 1504 --- [ctor-http-nio-2] reactor.netty.ReactorNetty : [id: 0xf50bdf8d, L:/127.0.0.1:62324 ! R:localhost/127.0.0.1:8990] Non Removed handler: WriteTimeoutHandler, context: ChannelHandlerContext(WriteTimeoutHandler, [id: 0xf50bdf8d, L:/127.0.0.1:62324 ! R:localhost/127.0.0.1:8990]), pipeline: DefaultChannelPipeline{(reactor.left.httpCodec = io.netty.handler.codec.http.HttpClientCodec), (reactor.left.decompressor = io.netty.handler.codec.http.HttpContentDecompressor), (WriteTimeoutHandler = io.netty.handler.timeout.WriteTimeoutHandler), (ReadTimeoutHandler = io.netty.handler.timeout.ReadTimeoutHandler), (reactor.right.reactiveBridge = reactor.netty.channel.ChannelOperationsHandler)}
2019-07-08 11:56:52.014 DEBUG [-,,,] 1504 --- [ctor-http-nio-2] r.netty.resources.NewConnectionProvider : [id: 0xf50bdf8d, L:/127.0.0.1:62324 ! R:localhost/127.0.0.1:8990] onStateChange([response_incomplete], GET{uri=/service/TWFDHF?T1=1.0.0&T2=1, connection=SimpleConnection{channel=[id: 0xf50bdf8d, L:/127.0.0.1:62324 ! R:localhost/127.0.0.1:8990]}})
2019-07-08 11:56:52.014 WARN [-,,,] 1504 --- [ctor-http-nio-2] reactor.netty.channel.FluxReceive : [id: 0xf50bdf8d, L:/127.0.0.1:62324 ! R:localhost/127.0.0.1:8990] An exception has been observed post termination
записи журнала с включенным прослушиванием
2019-07-10 14:51:19.295 DEBUG [-,,,] 2940 --- [ctor-http-nio-2] reactor.netty.tcp.TcpClient : [id: 0x677da0d4, L:/127.0.0.1:62385 ! R:localhost/127.0.0.1:8990] UNREGISTERED
2019-07-10 14:51:19.541 DEBUG [-,,,] 2940 --- [ctor-http-nio-4] reactor.netty.tcp.TcpClient : [id: 0xa7f41d1e, L:/127.0.0.1:62384 - R:localhost/127.0.0.1:8990] CLOSE
2019-07-10 14:51:19.542 DEBUG [-,,,] 2940 --- [ctor-http-nio-4] r.n.resources.PooledConnectionProvider : [id: 0xa7f41d1e, L:/127.0.0.1:62384 ! R:localhost/127.0.0.1:8990] Channel cleaned, now 0 active connections and 9 inactive connections
2019-07-10 14:51:19.542 DEBUG [-,,,] 2940 --- [ctor-http-nio-4] r.n.resources.PooledConnectionProvider : [id: 0xa7f41d1e, L:/127.0.0.1:62384 ! R:localhost/127.0.0.1:8990] Channel closed, now 0 active connections and 8 inactive connections
2019-07-10 14:51:19.542 DEBUG [-,,,] 2940 --- [ctor-http-nio-4] reactor.netty.ReactorNetty : [id: 0xa7f41d1e, L:/127.0.0.1:62384 ! R:localhost/127.0.0.1:8990] Non Removed handler: ReadTimeoutHandler, context: ChannelHandlerContext(ReadTimeoutHandler, [id: 0xa7f41d1e, L:/127.0.0.1:62384 ! R:localhost/127.0.0.1:8990]), pipeline: DefaultChannelPipeline{(reactor.left.loggingHandler = io.netty.handler.logging.LoggingHandler), (reactor.left.httpCodec = io.netty.handler.codec.http.HttpClientCodec), (WriteTimeoutHandler = io.netty.handler.timeout.WriteTimeoutHandler), (ReadTimeoutHandler = io.netty.handler.timeout.ReadTimeoutHandler), (reactor.right.reactiveBridge = reactor.netty.channel.ChannelOperationsHandler)}
2019-07-10 14:51:19.543 DEBUG [-,,,] 2940 --- [ctor-http-nio-4] reactor.netty.ReactorNetty : [id: 0xa7f41d1e, L:/127.0.0.1:62384 ! R:localhost/127.0.0.1:8990] Non Removed handler: WriteTimeoutHandler, context: ChannelHandlerContext(WriteTimeoutHandler, [id: 0xa7f41d1e, L:/127.0.0.1:62384 ! R:localhost/127.0.0.1:8990]), pipeline: DefaultChannelPipeline{(reactor.left.loggingHandler = io.netty.handler.logging.LoggingHandler), (reactor.left.httpCodec = io.netty.handler.codec.http.HttpClientCodec), (WriteTimeoutHandler = io.netty.handler.timeout.WriteTimeoutHandler), (ReadTimeoutHandler = io.netty.handler.timeout.ReadTimeoutHandler), (reactor.right.reactiveBridge = reactor.netty.channel.ChannelOperationsHandler)}
2019-07-10 14:51:19.543 DEBUG [-,,,] 2940 --- [ctor-http-nio-4] reactor.netty.tcp.TcpClient : [id: 0xa7f41d1e, L:/127.0.0.1:62384 ! R:localhost/127.0.0.1:8990] INACTIVE
2019-07-10 14:51:19.544 DEBUG [-,,,] 2940 --- [ctor-http-nio-4] r.n.resources.PooledConnectionProvider : [id: 0xa7f41d1e, L:/127.0.0.1:62384 ! R:localhost/127.0.0.1:8990] onStateChange(GET{uri=/dataviews/TWN_EMPLBENINFO_FIXED?version=1.0.0&sequence=1, connection=PooledConnection{channel=[id: 0xa7f41d1e, L:/127.0.0.1:62384 ! R:localhost/127.0.0.1:8990]}}, [response_incomplete])
2019-07-10 14:51:19.544 WARN [-,,,] 2940 --- [ctor-http-nio-4] reactor.netty.channel.FluxReceive : [id: 0xa7f41d1e, L:/127.0.0.1:62384 ! R:localhost/127.0.0.1:8990] An exception has been observed post termination
и мой куратор
protected Mono handleClientResponseError(final ClientResponse clientResponse) {
clientResponse.bodyToMono(Void.class);
Mono<ErrorResponse> errorResponse = clientResponse.body(BodyExtractors.toMono(ErrorResponse.class));
return errorResponse.flatMap(err -> {
log.debug("Received HttpStatusCodeException when calling {} Registry: {}", getGatewayName(),
err.getErrorEnvelope().getMessage());
return Mono.error(new UpStreamServiceHttpException(err, clientResponse.rawStatusCode()));
}).switchIfEmpty(Mono.error(() -> {
log.debug("Received HttpStatusCodeException when calling {} Registry: {}", getGatewayName());
return new UpStreamServiceHttpException("Bad Gateway", clientResponse.rawStatusCode());
}));
}
Я уже пробовал использовать clientResponse.bodyToMono(Void.class);
для завершения ответа, но он по-прежнему не работает, мне нужен способ завершить ответ от веб-клиента, а затем иметь возможность повторно использовать пул соединений и избавиться от этих сообщений журнала
Я создал проблему на github, но она была закрыта, поэтому я создаю этот вопрос здесь. https://github.com/spring-projects/spring-framework/issues/23249