8

在我们的网络应用程序中,用户可以提交一个 url。我们将获取数据并在服务器端解析它。对于每个请求,我们使用具有以下(相关)设置的 HttpClient

connectionManager.getParams().setConnectionTimeout(10000);
connectionManager.getParams().setSoTimeout(10000);

当我调用 HttpMethod.getResponseBody 时,状态代码已被检查为可接受。此时线程挂起此堆栈跟踪:

java.net.SocketInputStream.socketRead0 ( native code )
java.net.SocketInputStream.read ( SocketInputStream.java:150 )
java.net.SocketInputStream.read ( SocketInputStream.java:121 )
java.io.BufferedInputStream.read1 ( BufferedInputStream.java:273 )
java.io.BufferedInputStream.read ( BufferedInputStream.java:334 )
java.io.FilterInputStream.read ( FilterInputStream.java:133 )
org.apache.commons.httpclient.AutoCloseInputStream.read ( AutoCloseInputStream.java:108 )
java.io.FilterInputStream.read ( FilterInputStream.java:107 )
org.apache.commons.httpclient.AutoCloseInputStream.read ( AutoCloseInputStream.java:127 )
org.apache.commons.httpclient.HttpMethodBase.getResponseBody ( HttpMethodBase.java:690 )

我无法找到发生这种情况的确切 URL(是现场环境中的事件),并且我无法重现它。我想这只是我们连接的服务器行为异常的问题,但也许我错过了一些东西。在任何一种情况下,我有没有办法防止阻塞方法调用永远等待?SoTimeout 也是套接字读取超时?我还缺少其他设置吗?

4

5 回答 5

4

我的所有超时设置都很好,但我发现我们在 url 上进行了 http 分块但不发送任何结果(在 chrome 中工作正常,但在 http 客户端中,即使设置了超时,它也会永远挂起)。幸运的是我拥有服务器并且只是返回一些垃圾并且它不再挂起。这似乎是一个非常独特的错误,因为 http 客户端不能很好地处理某种空分块情况(尽管我可能会离开)....我只知道它每次都挂在具有空数据和该 url 的同一个 url是 http 分块 csv 下载回我们的 http 客户端。

于 2013-10-04T19:13:17.973 回答
0

我们在实现中始终如一地看到这一点,看起来 http 客户端没有正确处理坏服务器或其他东西,它没有超时.....我可以使用这个数据总线开源项目在我们的设置中重现,堆栈跟踪是有点不同……

SocketInputStream.socketRead0(FileDescriptor, byte[], int, int, int) line: 不可用 [native method]
SocketInputStream.read(byte[], int, int) line: 129
SocketInputBuffer(AbstractSessionInputBuffer).fillBuffer() line: 166
SocketInputBuffer.fillBuffer() 行:90 SocketInputBuffer(AbstractSessionInputBuffer).readLine(CharArrayBuffer) 行:281
DefaultHttpResponseParser.parseHead(SessionInputBuffer) 行:92
DefaultHttpResponseParser.parseHead(SessionInputBuffer) 行:62
DefaultHttpResponseParser(AbstractMessageParser).parse() 行:254
DefaultClientConnection (AbstractHttpClientConnection).receiveResponseHeader() 行:289 DefaultClientConnection.receiveResponseHeader() 行:252
BasicPooledConnAdapter(AbstractClientConnAdapter).receiveResponseHeader() 行:219 HttpRequestExecutor.doReceiveResponse(HttpRequest, HttpClientConnection, HttpContext) 行:300 HttpRequestExecutor.execute(HttpRequest, HttpClientConnection, HttpContext) 行:127
DefaultRequestDirector.tryExecute(RoutedRequest, HttpContext) 行:712 DefaultRequestDirector。执行(HttpHost,HttpRequest,HttpContext)行:517
DefaultHttpClient(AbstractHttpClient).execute(HttpHost,HttpRequest,HttpContext)行:906 DefaultHttpClient(AbstractHttpClient).execute(HttpUriRequest,HttpContext)行:805
ReadAggregations.processAggregation(字符串,计数器,计数器, Counter, Counter) 行: 153
ReadAggregations.start() 行: 96
ReadAggregations.main(String[]) 行: 70

于 2013-10-04T18:54:06.180 回答
0

您可以尝试使用 HttpUriRequest#abort() 中止请求,请参阅https://hc.apache.org/httpcomponents-client-4.3.x/httpclient/apidocs/org/apache/http/client/methods/HttpUriRequest.html #中止%28%29。但是,设置一个不需要拦截的超时会更好。这是一个相关的问题:Setting time out in apache http client

于 2014-04-24T09:38:46.177 回答
0

当我调用 HttpMethod.getResponseBody 时,状态代码已被检查为可接受。此时线程挂起

看起来您在同步调用时遇到问题...您应该确保该方法

HttpMethod.getResponseBody

被顺序调用或者应该对更改状态代码的部分使用互斥锁(信号量)

此外,您应该减少超时限制以防止挂起。

于 2013-04-08T08:59:28.797 回答
0

HttpClient 区分连接和请求。setSoTimeout将配置连接套接字超时,同时setConnectionTimeout将配置连接管理器的超时(等待连接的时间)和连接本身的建立。在您提供的代码中,您没有为用于请求本身的套接字设置任何超时,不幸的是,HttpClient 默认情况下没有超时。

这是我在 v4.4.1 中的做法:

// Configure the socket timeout for the connection, incl. ssl tunneling
connManager = new PoolingHttpClientConnectionManager();
connManager.setMaxTotal(200);
connManager.setDefaultMaxPerRoute(100);

SocketConfig sc = SocketConfig.custom()
    .setSoTimeout(soTimeoutMs)
    .build();

connManager.setDefaultSocketConfig(sc);

HttpClient client = HttpClients.custom()
            .setConnectionManager(connManager)
            .setConnectionManagerShared(true)
            .build();

// configure the timeouts (socket and connection) for the request
RequestConfig.Builder config = = RequestConfig.copy(RequestConfig.DEFAULT);
config.setConnectionRequestTimeout(connectionTimeoutMs);
config.setSocketTimeout(socketTimeoutMs);

HttpRequestBase req = new HttpGet(uri);
req.setConfig(config.build());

client.execute(req);
于 2016-01-04T18:59:46.837 回答