私は次のことをしているURLごとに、たくさんのURLをループしています。
private String doQuery(String url) {
HttpGet httpGet = new HttpGet(url);
setDefaultHeaders(httpGet); // static method
HttpResponse response = httpClient.execute(httpGet); // httpClient instantiated in constructor
int rc = response.getStatusLine().getStatusCode();
if (rc != 200) {
// some stuff...
return;
}
HttpEntity entity = response.getEntity();
if (entity == null) {
// some stuff...
return;
}
// process the entity, get input stream etc
}
最初のクエリは問題なく、2番目のクエリはこの例外をスローします。
スレッド「メイン」の例外Java.lang.IllegalStateException:SingleClientConnManagerの無効な使用:接続はまだ割り当てられています。別の接続を割り当てる前に、接続を必ず解放してください。 org.Apache.http.impl.conn.SingleClientConnManager.getConnection(SingleClientConnManager.Java:199)at org.Apache.http.impl.conn.SingleClientConnManager $ 1.getConnection(SingleClientConnManager.Java:173)......
これは単純なシングルスレッドアプリです。この接続を解除するにはどうすればよいですか?
私自身の質問に答えるには、接続(およびリクエストに関連付けられた他のリソース)を解放するには、HttpEntityによって返されたInputStreamを閉じる必要があります。
InputStream is = entity.getContent();
.... process the input stream ....
is.close(); // releases all resources
docs から
Httpcomponents 4.1で推奨される方法は、接続を閉じて、基になるリソースを解放することです。
EntityUtils.consume(HttpEntity)
ここで、渡されるHttpEntity
は応答エンティティです。
これはうまくいくようです:
if( response.getEntity() != null ) {
response.getEntity().consumeContent();
}//if
また、コンテンツを開かなかった場合でも、エンティティを使用することを忘れないでください。たとえば、応答からHTTP_OKステータスを期待し、それを取得しない場合、まだエンティティを消費する必要があります!
バージョン4.2以降、接続リリースを簡素化するはるかに便利なメソッドが導入されました。 HttpRequestBase.releaseConnection()
私は、Apache HttpClient 4.0.1に具体的に対処する詳細な回答を探しています。このHttpClientバージョンを使用しているのは、WAS v8.0によって提供されているためです。また、NTLM認証REST Sharepointを呼び出します。
Apache HttpClientメーリングリストでOleg Kalnichevskiを引用するには:
このコードはほとんど必要ありません。 (1)HttpClientは、エンティティコンテンツがストリームの最後まで消費される限り、基になる接続を自動的に解放します。 (2)HttpClientは、応答コンテンツの読み取り中にスローされたI/O例外の基になる接続を自動的に解放します。このような場合、特別な処理は必要ありません。
実際、これはリソースの適切なリリースを保証するために完全に十分です:
HttpResponse rsp = httpclient.execute(target, req); HttpEntity entity = rsp.getEntity(); if (entity != null) { InputStream instream = entity.getContent(); try { // process content } finally { instream.close(); // entity.consumeContent() would also do } }
それだ。
応答が消費されない場合、以下のコードを使用して要求を中止できます。
// Low level resources should be released before initiating a new request
HttpEntity entity = response.getEntity();
if (entity != null) {
// Do not need the rest
httpPost.abort();
}
参照: http://hc.Apache.org/httpcomponents-client-ga/tutorial/html/fundamentals.html#d5e14
Apache HttpClientバージョン:4.1.3
マルチスレッド環境(サーブレット)でHttpClientを使用すると、この問題が発生します。 1つのサーブレットがまだ接続を保持しており、別のサーブレットが接続を取得したい。
解決策:
バージョン4.0はThreadSafeClientConnManager
を使用します
バージョン4.2はPoolingClientConnectionManager
を使用します
この2つのセッターを設定します。
setDefaultMaxPerRoute
setMaxTotal
Response.getEntity()はnullであるため、HTTP HEADリクエストは少し異なる方法で処理する必要があります。代わりに、HttpClient.execute()に渡されたHttpContextをキャプチャし、接続パラメーターを取得して閉じます(とにかくHttpComponents 4.1.Xで)。
HttpRequest httpRqst = new HttpHead( uri );
HttpContext httpContext = httpFactory.createContext();
HttpResponse httpResp = httpClient.execute( httpRqst, httpContext );
...
// Close when finished
HttpEntity entity = httpResp.getEntity();
if( null != entity )
// Handles standard 'GET' case
EntityUtils.consume( entity );
else {
ConnectionReleaseTrigger conn =
(ConnectionReleaseTrigger) httpContext.getAttribute( ExecutionContext.HTTP_CONNECTION );
// Handles 'HEAD' where entity is not returned
if( null != conn )
conn.releaseConnection();
}
HttpComponents 4.2.Xでは、これを簡単にするためにHttpRequestBaseにreleaseConnection()が追加されました。
私はCloseableHttpClient#close
を使用してHttpClient 4.5.3を使用しています。
CloseableHttpResponse response = client.execute(request);
try {
HttpEntity entity = response.getEntity();
String body = EntityUtils.toString(entity);
checkResult(body);
EntityUtils.consume(entity);
} finally {
response.close();
}
接続を再利用する場合は、次のように使用するたびにコンテンツストリームを完全に消費する必要があります。
EntityUtils.consume(response.getEntity())
注:ステータスコードが200でない場合でも、コンテンツストリームを消費する必要があります。そうしないと、次の使用時に次のメッセージが表示されます。
スレッド「メイン」の例外Java.lang.IllegalStateException:SingleClientConnManagerの無効な使用:接続はまだ割り当てられています。別の接続を割り当てる前に、接続を必ず解放してください。
一度だけ使用する場合は、接続を閉じるだけで、それに関連付けられているすべてのリソースが解放されます。
ハンドラーを使用して応答を処理することを強くお勧めします。
client.execute(yourRequest,defaultHanler);
consume(HTTPENTITY)
メソッドで接続を自動的に解放します。
ハンドラーの例:
private ResponseHandler<String> defaultHandler = new ResponseHandler<String>() {
@Override
public String handleResponse(HttpResponse response)
throws IOException {
int status = response.getStatusLine().getStatusCode();
if (status >= 200 && status < 300) {
HttpEntity entity = response.getEntity();
return entity != null ? EntityUtils.toString(entity) : null;
} else {
throw new ClientProtocolException("Unexpected response status: " + status);
}
}
};
私は同じ問題を抱えていて、メソッドの最後で応答を閉じることで解決しました:
try {
// make the request and get the entity
} catch(final Exception e) {
// handle the exception
} finally {
if(response != null) {
response.close();
}
}