REST 保证 - org.apache.http.NoHttpResponseException: <server_address>:80 未能响应

REST Assured - org.apache.http.NoHttpResponseException: <server_address>:80 failed to respond

我间歇性地遇到 REST Assured 3.0.3 的这个问题,相应的代码行在 for 循环中。

这是一个简单的 GET 调用,如下所述:

response = given().setBaseUri(someBaseUri).setBasePath(someEndPoint).param("key", "value").header("X-Authorization-Token", my_auth_token).get();

我发现了几个建议使用 ConnectionConfig 解决问题的 Whosebug 答案,但我不知道如何在使用 REST Assured 时解决问题。

下面是完整的轨迹:

org.apache.http.NoHttpResponseException: <full_server_address> 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.AbstractHttpClientConnection.receiveResponseHeader(AbstractHttpClientConnection.java:283)
    at org.apache.http.impl.conn.DefaultClientConnection.receiveResponseHeader(DefaultClientConnection.java:259)
    at org.apache.http.impl.conn.ManagedClientConnectionImpl.receiveResponseHeader(ManagedClientConnectionImpl.java:209)
    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.client.DefaultRequestDirector.tryExecute(DefaultRequestDirector.java:686)
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:488)
    at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:884)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55)
    at org.apache.http.client.HttpClient$execute[=13=].call(Unknown Source)
    at io.restassured.internal.RequestSpecificationImpl$RestAssuredHttpBuilder.doRequest(RequestSpecificationImpl.groovy:2122)
    at io.restassured.internal.http.HTTPBuilder.doRequest(HTTPBuilder.java:494)
    at io.restassured.internal.http.HTTPBuilder.request(HTTPBuilder.java:451)
    at io.restassured.internal.http.HTTPBuilder$request.call(Unknown Source)
    at io.restassured.internal.RequestSpecificationImpl.sendHttpRequest(RequestSpecificationImpl.groovy:1525)
    at sun.reflect.GeneratedMethodAccessor152.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1218)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1027)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:815)
    at io.restassured.internal.RequestSpecificationImpl.invokeMethod(RequestSpecificationImpl.groovy)
    at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.call(PogoInterceptableSite.java:48)
    at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.callCurrent(PogoInterceptableSite.java:58)
    at io.restassured.internal.RequestSpecificationImpl.sendRequest(RequestSpecificationImpl.groovy:1288)
    at sun.reflect.GeneratedMethodAccessor97.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1218)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1027)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:815)
    at io.restassured.internal.RequestSpecificationImpl.invokeMethod(RequestSpecificationImpl.groovy)
    at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.call(PogoInterceptableSite.java:48)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:149)
    at io.restassured.internal.filter.SendRequestFilter.filter(SendRequestFilter.groovy:30)
    at io.restassured.filter.Filter$filter[=13=].call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
    at io.restassured.filter.Filter$filter.call(Unknown Source)
    at io.restassured.internal.filter.FilterContextImpl.next(FilterContextImpl.groovy:72)
    at io.restassured.filter.time.TimingFilter.filter(TimingFilter.java:56)
    at io.restassured.filter.Filter$filter.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
    at io.restassured.filter.Filter$filter[=13=].call(Unknown Source)
    at io.restassured.internal.filter.FilterContextImpl.next(FilterContextImpl.groovy:72)
    at io.restassured.filter.FilterContext$next.call(Unknown Source)
    at io.restassured.internal.RequestSpecificationImpl.applyPathParamsAndSendRequest(RequestSpecificationImpl.groovy:1725)
    at sun.reflect.GeneratedMethodAccessor91.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1218)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1027)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:815)
    at io.restassured.internal.RequestSpecificationImpl.invokeMethod(RequestSpecificationImpl.groovy)
    at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.call(PogoInterceptableSite.java:48)
    at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.callCurrent(PogoInterceptableSite.java:58)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:182)
    at io.restassured.internal.RequestSpecificationImpl.applyPathParamsAndSendRequest(RequestSpecificationImpl.groovy:1731)
    at sun.reflect.GeneratedMethodAccessor90.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1218)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1027)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:815)
    at io.restassured.internal.RequestSpecificationImpl.invokeMethod(RequestSpecificationImpl.groovy)
    at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.call(PogoInterceptableSite.java:48)
    at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.callCurrent(PogoInterceptableSite.java:58)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:182)
    at io.restassured.internal.RequestSpecificationImpl.get(RequestSpecificationImpl.groovy:168)
    at io.restassured.internal.RequestSpecificationImpl.get(RequestSpecificationImpl.groovy)
    at sun.reflect.GeneratedMethodAccessor150.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1218)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1027)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:815)
    at io.restassured.internal.RequestSpecificationImpl.invokeMethod(RequestSpecificationImpl.groovy)
    at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.call(PogoInterceptableSite.java:48)
    at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.callCurrent(PogoInterceptableSite.java:58)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:166)
    at io.restassured.internal.RequestSpecificationImpl.get(RequestSpecificationImpl.groovy:252)
    at io.restassured.internal.RequestSpecificationImpl.get(RequestSpecificationImpl.groovy)

请帮忙

添加这段代码似乎解决了这个问题。即使使用速度较慢的暂存测试服务器,我也没有遇到过这个问题。

Response response = given()...get();
ConnectionConfig connectionConfig = new ConnectionConfig();
connectionConfig.closeIdleConnectionsAfterEachResponse();

不过我不明白的是,ConnectionConfig 对象如何与 Response 对象一起工作。

如果您了解 RestAssured http 连接建立机制,RestAssuredConfig 的每个新对象都会创建与服务器的新 httpclient 连接。对于少数 API 调用,可能会以块的形式接收到响应,在这种情况下,服务器可能会间歇性地关闭连接,并且由于此连接处于陈旧状态和 NoHttpResponse,客户端不知道它错误被抛出。 要处理此间歇性问题,最好的方法是使用一些重试机制来创建新的 http 连接并关闭之前发生 NoHttpResponseException 的连接。

更好的代码示例:

given().config(RestAssuredConfig.config().connectionConfig(
    ConnectionConfig.connectionConfig().closeIdleConnectionsAfterEachResponse()
)

Apache Http Client 5.0 中存在相同问题

org.apache.hc.core5.http.NoHttpResponseException: localhost:8443 failed to respond

解决PoolingHttpClientConnectionManager关闭空闲连接的问题

PoolingHttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create()
cm.closeIdle(TimeValue.ofMilliseconds(10));