【发布时间】:2019-08-13 23:46:42
【问题描述】:
我正在使用 HttpComponentsClientHttpRequestFactory 与 http-outbound-gateway 的 spring 集成。我遇到以下异常 NoHttpResponseException。
2019-08-13 16:09:51,839 http-bio-8443-exec-439 ERROR LoggingHandler:184 - org.springframework.messaging.MessageHandlingException: HTTP request execution failed for URI [https://my-service.com/my-service]; nested exception is org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://my-service.com/my-service": my-service:443 failed to respond; nested exception is org.apache.http.NoHttpResponseException: my-service.com:443 failed to respond
at org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler.handleRequestMessage(HttpRequestExecutingMessageHandler.java:409)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:109)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)
Caused by: org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://my-service.com/my-service": my-service.com:443 failed to respond; nested exception is org.apache.http.NoHttpResponseException: my-service.com:443 failed to respond
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:633)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:595)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:516)
at org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler.handleRequestMessage(HttpRequestExecutingMessageHandler.java:382)
... 213 more
Caused by: org.apache.http.NoHttpResponseException: my-service.com:443 failed to respond
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:143)
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:57)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:261)
at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:165)
at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:167)
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:272)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:124)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:271)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55)
at org.springframework.http.client.HttpComponentsClientHttpRequest.executeInternal(HttpComponentsClientHttpRequest.java:91)
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:619)
... 216 more
四处搜索我发现这个link 是问题的陈旧连接,所以我想按照文档中的说明驱逐它们
经典阻塞 I/O 模型的主要缺点之一是网络套接字只有在 I/O 操作中阻塞时才能对 I/O 事件做出反应。当连接释放回管理器时,它可以保持活动状态,但是它无法监视套接字的状态并对任何 I/O 事件做出反应。如果连接在服务器端关闭,则客户端连接无法检测到连接状态的变化(并通过关闭其末端的套接字来做出适当的反应)。
HttpClient 试图通过测试是否 连接“陈旧”,不再有效,因为它已关闭 在服务器端,在使用连接执行 HTTP 请求。陈旧的连接检查不是 100% 可靠的。这 唯一可行的解决方案,不涉及每个套接字一个线程 空闲连接的模型是用于驱逐的专用监视器线程 由于长时间的连接而被视为过期的连接 不活动。监控线程可以定期调用 ClientConnectionManager#closeExpiredConnections() 方法关闭所有 过期的连接并从池中逐出关闭的连接。它可以 还可以选择调用 ClientConnectionManager#closeIdleConnections() 关闭所有在给定时间空闲的连接的方法 一段时间。
<int-http:outbound-gateway id="httpOutboundGateway" request-channel="requestServiceHttpChannel"
reply-channel="responseServiceHttpChannel" url-expression="headers.serviceUrl" http-method="POST"
expected-response-type="java.lang.String" charset="UTF-8" request-factory="httpOutboundRequestFactoryBean"
message-converters="messageConverterList" header-mapper="headerMapperBean"/>
<bean id="httpOutboundRequestFactoryBean"
class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
<property name="readTimeout" value="${http.service.timeout.readResponse}"/>
<property name="connectTimeout" value="${http.service.timeout.connection}"/>
</bean>
不幸的是,Spring 抽象仅提供修改超时,但我无法更改池配置或访问池管理器来完成 http client docs 所说的那样。
一种选择是扩展 HttpComponentsClientHttpRequestFactory 并添加方法以从 cron 作业访问 HttpClientConnectionManager 以清除陈旧的连接,但也许您知道更好的选择
是否有一个 spring 集成抽象我可以使用来自 apache 的 HTTPClient 来清理 http-outboung-gateway 上的陈旧连接?
【问题讨论】:
标签: spring-integration connection-pooling apache-httpclient-4.x