developer tip

HttpClient 4.0.1-연결 해제 방법?

optionbox 2020. 10. 31. 09:37
반응형

HttpClient 4.0.1-연결 해제 방법?


여러 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

}

첫 번째 쿼리는 괜찮고 두 번째 쿼리는 다음 예외를 발생시킵니다.

스레드 "main"의 예외 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) ......

이것은 단순한 단일 스레드 앱입니다. 이 연결을 어떻게 해제 할 수 있습니까?


Httpcomponents 4.1에서 권장하는 방법은 연결을 닫고 기본 리소스를 해제하는 것입니다.

EntityUtils.consume(HttpEntity)

HttpEntity전달 된 은 응답 엔터티입니다.


이것은 잘 작동하는 것 같습니다.

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

그리고 콘텐츠를 열지 않았더라도 엔티티를 소비하는 것을 잊지 마십시오. 예를 들어, 응답에서 HTTP_OK 상태를 예상하고 얻지 못하더라도 여전히 엔티티를 소비해야합니다!


내 질문에 답하려면 연결 (및 요청과 관련된 다른 리소스)을 해제하려면 HttpEntity에서 반환 한 InputStream을 닫아야합니다.

InputStream is = entity.getContent();

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

is.close();       // releases all resources

로부터 문서


버전 4.2부터 연결 해제를 단순화하는 훨씬 더 편리한 메서드 인 HttpRequestBase.releaseConnection ()을 도입했습니다.


Apache HttpClient 4.0.1을 구체적으로 다루는 자세한 답변을 들었습니다. 이 HttpClient 버전은 WAS v8.0에서 제공하므로 WAS v8.0에서도 제공하는 Apache Wink v1.1.1 내에서 제공된 HttpClient를 사용하여 Sharepoint에 대한 NTLM 인증 REST 호출을 수행해야합니다. .

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#d5e143

Apache HttpClient 버전 : 4.1.3


다중 스레드 환경 (서블릿)에서 HttpClient를 사용할 때이 문제가 발생합니다. 한 서블릿은 여전히 ​​연결을 유지하고 다른 서블릿은 연결을 원합니다.

해결책:

버전 4.0 사용 ThreadSafeClientConnManager

버전 4.2 사용 PoolingClientConnectionManager

이 두 setter를 설정합니다.

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 ()을 추가했습니다.


I'm using HttpClient 4.5.3, using CloseableHttpClient#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();
    }

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.


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

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

참고URL : https://stackoverflow.com/questions/4775618/httpclient-4-0-1-how-to-release-connection

반응형