开发者

HttpClient 4.0.1 - how to release connection? [duplicate]

开发者 https://www.devze.com 2023-02-06 02:01 出处:网络
This question already has answers here: What is the difference between CloseableHttpClient and HttpClient in Apache HttpClient API?
This question already has answers here: What is the difference between CloseableHttpClient and HttpClient in Apache HttpClient API? (8 answers) Closed 2 years ago.

I have a loop over a bunch of URLs, for each one I'm doing the following:

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开发者_C百科, get input stream etc

}

The first query is fine, the second throws this exception:

Exception in thread "main" java.lang.IllegalStateException: Invalid use of SingleClientConnManager: connection still allocated. Make sure to release the connection before allocating another one. at org.apache.http.impl.conn.SingleClientConnManager.getConnection(SingleClientConnManager.java:199) at org.apache.http.impl.conn.SingleClientConnManager$1.getConnection(SingleClientConnManager.java:173)......

This is just a simple single-threaded app. How can I release this connection?


The recommended way, by Httpcomponents 4.1, is to close connection and release any underlying resources:

EntityUtils.consume(HttpEntity)

where HttpEntity passed is a response entity.


This seems to work great :

      if( response.getEntity() != null ) {
         response.getEntity().consumeContent();
      }//if

And don't forget to consume the entity even if you didn't open its content. For instance, you expect a HTTP_OK status from the response and don't get it, you still have to consume the entity !


To answer my own question: to release the connection (and any other resources associated with the request) you must close the InputStream returned by the HttpEntity:

InputStream is = entity.getContent();

.... process the input stream ....

is.close();       // releases all resources

From the docs


Since version 4.2, they introduced a much more convenience method that simplifies connection release: HttpRequestBase.releaseConnection()


I'm chiming in with a detailed answer that specifically addresses Apache HttpClient 4.0.1. I'm using this HttpClient version, since it's provided by WAS v8.0, and I need to use that provided HttpClient within Apache Wink v1.1.1, also provided by WAS v8.0, to make some NTLM-authenticated REST calls to Sharepoint.

To quote Oleg Kalnichevski on the Apache HttpClient mailing list:

Pretty much all this code is not necessary. (1) HttpClient will automatically release the underlying connection as long as the entity content is consumed to the end of stream; (2) HttpClient will automatically release the underlying connection on any I/O exception thrown while reading the response content. No special processing is required in such as case.

In fact, this is perfectly sufficient to ensure proper release of resources:

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
     } 
}

That is it.

Source


If the response is not to be consumed, then the request can be aborted using the code below:

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

Reference: http://hc.apache.org/httpcomponents-client-ga/tutorial/html/fundamentals.html#d5e143

Apache HttpClient Version: 4.1.3


I've got this problem when I use HttpClient in Multithread envirnoment (Servlets). One servlet still holds connection and another one want to get connection.

Solution:

version 4.0 use ThreadSafeClientConnManager

version 4.2 use PoolingClientConnectionManager

and set this two setters:

setDefaultMaxPerRoute
setMaxTotal


I'm using HttpClient 4.5.3, using CloseableHttpResponse#close worked for me.

    CloseableHttpResponse response = client.execute(request);

    try {
        HttpEntity entity = response.getEntity();
        String body = EntityUtils.toString(entity);
        checkResult(body);
        EntityUtils.consume(entity);
    } finally {
        response.close();
    }

With Java7 and beyond:

try (CloseableHttpResponse response = client.execute(request)) {
   ...
}


HTTP HEAD requests must be treated slightly differently because response.getEntity() is null. Instead, you must capture the HttpContext passed into HttpClient.execute() and retrieve the connection parameter to close it (in HttpComponents 4.1.X anyway).

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 added a releaseConnection() to HttpRequestBase to make this easier.


If you want to re-use the connection then you must consume content stream completely after every use as follows :

EntityUtils.consume(response.getEntity())

Note : you need to consume the content stream even if the status code is not 200. Not doing so will raise the following on next use :

Exception in thread "main" java.lang.IllegalStateException: Invalid use of SingleClientConnManager: connection still allocated. Make sure to release the connection before allocating another one.

If it's a one time use, then simply closing the connection will release all the resources associated with it.


Highly recommend using a handler to handle the response.

client.execute(yourRequest,defaultHanler);

It will release the connection automatically with consume(HTTPENTITY) method.

A handler example:

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


I had the same issue and solved it by closing the response at the end of the method:

try {
    // make the request and get the entity 
} catch(final Exception e) {
    // handle the exception
} finally {
    if(response != null) {
        response.close();
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消