2012-03-29 192 views
20

我正在開發一個長時間運行的應用程序,大量使用來自Apache的HttpClient。HttpClient卡住沒有任何異常

在我的第一次測試運行中,應用程序工作完美,直到它卡住了。它沒有停止,它沒有拋出任何異常,它只是坐在那裏無所事事。

我剛剛做了第二次運行,並停止了時間,大約在第二次運行後停止。 24小時運行。此外,我注意到我運行的筆記本電腦的互聯網連接在應用程序卡住的時刻終止。我必須重新啓動我的WLAN適配器才能再次運行網絡。

雖然應用程序在連接重新啓動後沒有恢復工作。而現在,它又被卡住了。

是否有任何超時控制器,我不知道在HttpClient中?爲什麼我的應用程序在連接斷開時不會引發異常?

使用客戶端的部分如下所示;

public HttpUtil(ConfigUtil config) { 
    this.config = config; 

    client = new DefaultHttpClient(); 
    client.getParams().setParameter(HttpProtocolParams.USER_AGENT, this.config.getProperty("httputil.userAgent")); 
} 

public String getContentAsString(String url) throws ParseException, ClientProtocolException, IOException { 
    return EntityUtils.toString(
      client.execute(
        new HttpGet(url)).getEntity()); 
} 

該應用程序在需要的URL上重複調用httputil.getContentAsString()

+0

也許你的實體是一個空字符串。 – kasavbere 2012-03-29 12:20:11

+0

然後我的方法仍然會返回那個空字符串,不是嗎?或者至少拋出異常? – 2012-03-29 12:31:37

+1

我有同樣的問題。 httpEntity.consumeContent()救我。 http://stackoverflow.com/questions/9505358/android-httpclient-hangs-on-second-request-to-the-server-connection-timed-out – JamesC 2015-02-25 08:57:29

回答

8

此代碼現已被棄用(獲得HttpParams等)。更好的方法是:

RequestConfig defaultRequestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.BEST_MATCH).setExpectContinueEnabled(true).setStaleConnectionCheckEnabled(true).setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM, AuthSchemes.DIGEST)).setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC)).build(); 

HttpGet httpGet = new HttpGet(url);  
RequestConfig requestConfig = RequestConfig.copy(defaultRequestConfig).setSocketTimeout(5000).setConnectTimeout(5000).setConnectionRequestTimeout(5000).build(); 
httpGet.setConfig(requestConfig); 
6

你還沒有說過你正在使用哪個版本的HttpClient,但假設它是版本4,this blog article解釋了該怎麼做。

DefaultHttpClient httpClient = new DefaultHttpClient(); 
HttpParams params = httpClient.getParams(); 
HttpConnectionParams.setConnectionTimeout(httpParams, connectionTimeoutMillis); 
HttpConnectionParams.setSoTimeout(httpParams, socketTimeoutMillis); 
+2

我相信這是現在不推薦使用 – 2014-12-11 16:23:50

3

默認情況下,HttpClient不超時(這會導致更多的問題,而不是幫助)。你所描述的可能是一個硬件問題,如果你的網絡適配器死了,HttpClient會掛起。

下面是parameters設置爲HttpParams作爲構造的一部分,以DefaultHttpClient包括

http.socket.timeout:定義插座超時(SO_TIMEOUT)在 毫秒,這是等待超時對於數據或者以不同的方式,將兩個連續數據分組之間的最大週期不活動性)分組。超時值爲零被解釋爲無限的 超時。該參數需要java.lang.Integer類型的值。如果 未設置此參數,則讀操作不會超時(無限 超時)。

這將在連接上設置一個超時,所以在設置超時之後會拋出一個異常。

3

我所有的超時設置得很好,但我發現我們有URL,做HTTP分塊,不發送結果(鉻工作正常,但在HTTP客戶端甚至與超時設置永遠掛起)。幸運的是,我擁有服務器,只是返回一些垃圾,它不再掛起。這似乎是一個非常獨特的錯誤,因爲http客戶端並沒有很好地處理某種空塊(儘管我可能會離開)....我只知道它每次都掛在同一個具有空數據的url上,並且該url是http chunking csv下載回我們的http客戶端。

6

從版本4.4開始,用戶user2393012和Stephen C的答案都已被棄用。我不確定是否有另一種方式來完成它,但我這樣做的方式是使用構建器範例HTTPClientBuilder。

Ex。

HttpClients.custom().setConnectionTimeToLive(1, TimeUnit.MINUTES).build() 

非常相似(它實際上可能是OP的問題)問題是什麼OP也提到,但發生是由於Apache的默認併發連接數設置爲每個客戶端只有兩個連接。解決方法是增加最大連接數或者如果可以的話關閉它們。

要增加最大連接數:

HttpClients.custom().setMaxConnPerRoute(100000).build() 

關閉連接,你可以使用一個BasicHttpClientConnectionManager並呼籲關閉方法

3

我有同樣的問題,它堅持,因爲我沒有關閉DefaultHttpClient。
因此,這是錯誤的:

try{ 
    DefaultHttpClient httpclient = new DefaultHttpClient(); 
    ... 
} catch (Exception e){ 
    e.PrintStackTrace(); 
} 

這是正確的:

try (DefaultHttpClient httpclient = new DefaultHttpClient()){ 
    ... 
} catch (Exception e){ 
    e.PrintStackTrace(); 
} 

希望它可以幫助別人。

4

我在另一個線程(HttpClient hangs on socketRead0 with successfully executed method

在我的情況,我設置爲ConnectionTimeout和了socketTimeout上的要求,但不建立SSL連接時使用的連接插座上給出了類似的回答。因此,我有時會在SSL握手期間掛起。下面是一些使用v4.4設置所有3個超時的代碼(也在v4.5中測試過)

// 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);