【问题标题】:Config specific HTTPClient properties in HttpComponentsClientHttpRequestFactory在 HttpComponentsClientHttpRequestFactory 中配置特定的 HTTPClient 属性
【发布时间】: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


    【解决方案1】:

    Spring Integration 目前没有,但如果您想贡献一些东西,我们很乐意添加它。

    虽然我不会使用每 5 秒唤醒一次的专用线程,但我会使用 Spring Integration 的内置任务调度程序,具有可配置的调度和过期空闲时间。

    不过,您似乎不需要扩展工厂;你可以使用factory.getHttpClient().getConnectionManager() - 虽然我看到它已被弃用,所以工厂可能需要更新以使用更新的 API。

    但是,那是另一回事;可能应该针对 Spring Framework 本身提出一些问题。

    【讨论】:

    • 谢谢加里!由于不推荐使用的方法,我考虑了一个子类。我们如何才能不弃用该方法?我对贡献感兴趣,这样做的步骤是什么?
    • 这需要首先对spring framework 做出贡献,以替换/更新工厂以使用新的 API。也许过期也属于那里。我建议第一步是在 GitHub 上打开一个问题,以获得该团队的反馈——在你有兴趣贡献的问题中提及。
    猜你喜欢
    • 2016-07-12
    • 1970-01-01
    • 2019-06-28
    • 1970-01-01
    • 2020-12-21
    • 2022-01-05
    • 2022-01-18
    • 1970-01-01
    • 2016-09-15
    相关资源
    最近更新 更多