我使用Web-flux/Reactive和Webclient,在Tomcat和spring-boot上运行它。
一切正常。我读了很多关于它的文章。问题似乎是,无论何时使用webclient,你都必须返回或使用响应,否则它将关闭连接,你还没有使用它,你会看到很多日志消息说the connection close prematurely
,如果我有一个404状态代码是错误的场景,我可以只使用OnStatus
并抛出一个异常,但我的设想是当上游服务返回一个404,我必须手动返回一个mono空.所以我不使用来自web客户端请求的响应,我只是使用来自.exchange的ClientResponse()来检查状态并处理它。我最初的问题是日志消息,因为它只是“垃圾”,你不想在你的日志信息中看到太多这样的东西。我在哪里读到过,如果发生这样的情况,连接也不能重复使用,所以听起来很糟糕,但我不知道......当未找到时,我只收到此消息,如果响应为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);
来完成响应,但它仍然不起作用,我需要一种方法来完成来自Web客户端的响应,然后能够重用连接池并摆脱那些日志消息
我在github上创建了一个问题,但是它已经关闭了,所以我在这里创建了这个问题。https://github.com/spring-projects/spring-framework/issues/23249
3条答案
按热度按时间k3fezbri1#
所以我终于找到了一种方法来完成回应,我将在这里分享给任何遇到这个问题的人
在我有这个之前
但它没有工作,显然是因为我不返回它无论如何,所以在挖掘后,我尝试了这个:
而且工作正常,我查了窃听日志现在一切看起来都很好。
fdx2calv2#
我有同样的问题,我一直在斗争了5天,想知道到底是什么我做错了后,一个新的功能部署。我终于有我的Eureka 时刻。
因此,在我的 Dockerfile 中,我公开了默认端口 8080。
x1c 0d1x这意味着应用程序映像中的tomcat服务器在该端口上始终可用。我的容器也必须在端口8080上运行(在我的.yml文件中)
在应用端口Map指令将Linux主机上的外部端口9003Map到容器中的8080之前。
我遗漏的是,在使用docer-compose文件部署服务的过程中,我忘记了将application.yml文件中的server.port更改为8080,以便可以进行端口Map。(因为我在本地机器上使用9003来测试应用程序)* 这意味着每当我使用docker-compose启动容器时,我的服务端口都Map为
0.0.0.0版本:9003 -〉9003/传输控制协议,而不是***0.0.0.0版本:9003 -〉8080/传输控制协议***。
这就是为什么api网关不断抛出
提前关闭异常:连接过早关闭
因为实际上在我的微服务的容器示例中没有找到Linux主机上的9003要Map到的内部端口9003。
我只需要将我的应用程序中的9003改为8080,就这样。
rsl1atfo3#
我已经在我的Tests中解决了这个问题,方法是在每个方法的末尾添加以下代码行: