2017-09-05 99 views
0

在我的測試應用程序,我執行連續HTTPGET請求到同一個主機與的Apache的HttpClient但在每次下一個請求事實證明,以前的HttpConnection被關閉,新的HttpConnection創建。如何獲得與Apache HttpClient的持久HttpConnection?

我使用HttpClient的同一個實例並且不關閉響應。從每個實體我得到InputStream,用掃描儀讀取它,然後關閉掃描儀。我測試了KeepAliveStrategy,它返回true。請求之間的時間不超過keepAlive或connectionTimeToLive持續時間。

有誰能告訴我可能是什麼原因導致這種行爲?

更新

我已經找到了解決辦法。爲了使HttpConnecton保持活動狀態,需要在構建HttpClient時設置HttpClientConnectionManager。我已經使用BasicHttpClientConnectionManager

ConnectionKeepAliveStrategy keepAliveStrat = new DefaultConnectionKeepAliveStrategy() { 
    @Override 
    public long getKeepAliveDuration(HttpResponse response, HttpContext context) 
    { 
     long keepAlive = super.getKeepAliveDuration(response, context); 
     if (keepAlive == -1) 
     keepAlive = 120000; 
     return keepAlive; 
    } 
}; 
HttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(); 
try (CloseableHttpClient httpClient = HttpClients.custom() 
      .setConnectionManager(connectionManager) // without this setting connection is not kept alive 
      .setDefaultCookieStore(store) 
      .setKeepAliveStrategy(keepAliveStrat) 
      .setConnectionTimeToLive(120, TimeUnit.SECONDS) 
      .setUserAgent(USER_AGENT) 
      .build()) 
{ 
    HttpClientContext context = new HttpClientContext(); 
    RequestConfig config = RequestConfig.custom() 
      .setCookieSpec(CookieSpecs.DEFAULT) 
      .setSocketTimeout(10000) 
      .setConnectTimeout(10000) 
      .build(); 
    context.setRequestConfig(config); 
    HttpGet httpGet = new HttpGet(uri); 
    CloseableHttpResponse response = httpClient.execute(httpGet, context); 
    HttpConnection conn = context.getConnection(); 
    HttpEntity entity = response.getEntity(); 
    try (Scanner in = new Scanner(entity.getContent(), ENC)) 
    { 
     // do something 
    } 
    System.out.println("open=" + conn.isOpen()); // now open=true 

    HttpGet httpGet2 = new HttpGet(uri2); // on the same host with other path 

    // and so on 
} 

更新2

一般檢查連接與conn.isOpen()是不檢查的連接狀態,因爲正確的方法:「內部HTTP連接管理器與作爲代理一個真正ManagedHttpClientConnection的情況下工作連接管理連接狀態並控制I/O操作的執行如果託管連接被釋放或被其消費者明確關閉,則底層連接從其代理中分離出來並返回給管理器即使服務使用者stil l持有對代理實例的引用,它不再能夠有意或無意地執行任何I/O操作或更改真實連接的狀態。「HttpClent Tutorial

正如@oleg指出的那樣,跟蹤連接的正確方法是使用logger

+0

你能告訴我們一些代碼嗎? – inovaovao

+0

是的。我已經添加了該代碼。 – snptc

回答

1

首先,您需要確保您正在使用的遠程服務器確實支持保持連接。只需檢查遠程服務器是否在每個響應中都返回標頭Connection: Keep-AliveConnection: Closed。對於Close的情況下there is nothing你可以做到這一點。您可以使用this online tool執行此類檢查。

接下來,您需要實施this manual的第2.6段中定義的ConnectionKeepAliveStrategy。請注意,您可以使用存在DefaultConnectionKeepAliveStrategysince HttpClient version 4.0,讓您的HttpClient將構造如下:

HttpClient client = HttpClients.custom() 
    .setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE) 
    .build(); 

這將確保你HttpClient例如將重用通過保持活動的機制相同的連接,如果它是由服務器支持。

+0

謝謝你的回答。服務器返回Connection:keep-alive,並使用ConnectionKeepAliveStrategy。這就是爲什麼我不明白合成關閉的原因... – snptc

+0

你可以請發表一個方法或一段代碼構造http客戶端,然後發送連續獲取? – Kostiantyn

+0

是的。我已經添加了該代碼。 – snptc

0

您的應用程序必須正在關閉響應對象以確保正確的資源釋放底層連接。在響應結束後,HttpClient保持有效連接處於活動狀態,並將它們返回給連接管理器(連接池)。

我懷疑你的代碼只是泄漏了連接,並且每一個請求都被一個新創建的連接所阻擋,而所有以前的連接都在內存中堆積。

+0

** oleg:** *「您的應用程序必須關閉響應對象才能確保正確的資源釋放底層連接。」*從官方的[HttpClient教程](https://hc.apache.org/ httpcomponents-client-ga/tutorial/html/fundamentals.html#d5e145):*「關閉內容流和關閉響應的區別在於前者會嘗試通過消耗實體內容來保持底層連接的活動,而後者立即關閉並丟棄連接。「*這就是爲什麼我關閉InputStream而不是響應本身。 – snptc

+0

我知道教程說什麼。我看不到你的代碼在任何地方關閉InputStream。我確實看到Scanner正在關閉,但我不確定是否也會導致InputStream關閉。關閉響應可確保連接返回到池_不管是什麼,並且是最佳實踐。 – oleg

+0

如果您確信您的代碼沒有泄漏連接,請按照http://hc.apache.org/httpcomponents-client-4.5.x/logging.html中所述打開連接管理/請求執行日誌記錄,然後運行它。查看連接在釋放回池後是否保持活動狀態 – oleg

0

從例如在HttpClient website

// In order to ensure correct deallocation of system resources 
// the user MUST call CloseableHttpResponse#close() from a finally clause. 
// Please note that if response content is not fully consumed the underlying 
// connection cannot be safely re-used and will be shut down and discarded 
// by the connection manager. 

因此,作爲@oleg說,你需要檢查連接狀態之前關閉的HttpResponse。

+0

我試過了。結果是一樣的...此外,HttpClient教程指出,關閉響應將關閉底層連接(請參閱上面的註釋)。 – snptc