[java] HttpRequest.execute () 사용 예외 : SingleClientConnManager의 잘못된 사용 : 연결이 여전히 할당 됨

google-api-client-java 1.2.1-alpha를 사용하여 POST 요청을 실행하고 HttpRequest를 execute () 할 때 다음 스택 추적을 얻습니다.

이전 POST에서 동일한 URL 로의 403 오류를 포착하고 무시하고 후속 요청을 위해 전송을 재사용 한 직후에 발생합니다. (동일한 ATOM 피드에 여러 항목을 삽입하는 루프에 있습니다.)

403 이후 ‘정리’하기 위해해야 ​​할 일이 있습니까?

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)
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:390)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:641)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:576)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:554)
    at com.google.api.client.apache.ApacheHttpRequest.execute(ApacheHttpRequest.java:47)
    at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:207)
    at au.com.machaira.pss.gape.RedirectHandler.execute(RedirectHandler.java:38)
    at au.com.machaira.pss.gape.ss.model.records.TableEntry.executeModification(TableEntry.java:81)

아래 코드가 연결 을 얻으려고하는 이유는 무엇 입니까?



답변

다른 요청에 연결을 재사용하려면 먼저 응답 본문을 사용해야합니다. 응답 상태를 읽을뿐만 아니라 읽은 InputStream바이트를 무시하는 마지막 바이트까지 응답을 완전히 읽어야합니다.


답변

Jetty와 함께 HttpClient를 사용하여 테스트 프레임 워크를 구축 할 때 비슷한 문제에 직면했습니다. 클라이언트에서 Servelet에 여러 요청을 작성해야했지만 실행시 동일한 예외가 발생했습니다.

http://foo.jasonhudgins.com/2010/03/http-connections-revisited.html 에서 대안을 찾았습니다.

이 다음 방법을 사용하여 클라이언트를 인스턴스화 할 수도 있습니다.

public static DefaultHttpClient getThreadSafeClient()  {

    DefaultHttpClient client = new DefaultHttpClient();
    ClientConnectionManager mgr = client.getConnectionManager();
    HttpParams params = client.getParams();
    client = new DefaultHttpClient(new ThreadSafeClientConnManager(params,

            mgr.getSchemeRegistry()), params);
    return client;
}


답변

유사한 예외 메시지 (적어도 Apache Jarkata Commons HTTP Client 4.2 이후)는 다음과 같습니다.

java.lang.IllegalStateException: Invalid use of BasicClientConnManager: connection still allocated.
Make sure to release the connection before allocating another one.

이 예외는 둘 이상의 스레드가 단일 org.apache.http.impl.client.DefaultHttpClient.

어떻게 당신은 4.2 만들 수 있습니다 DefaultHttpClient(인스턴스 스레드 스레드 두 개 이상의 스레드가 오류 메시지가 위받지 않고 상호 작용할 수 있다는 의미에서)을? 형식으로 DefaultHttpClient연결 풀링 ClientConnectionManager을 제공하십시오 org.apache.http.impl.conn.PoolingClientConnectionManager!

/* using
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.2.2</version>
    </dependency>
*/

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.impl.conn.SchemeRegistryFactory;
import org.apache.http.params.HttpParams;
import org.apache.http.client.methods.HttpGet;

public class MyComponent {

    private HttpClient client;

    {
        PoolingClientConnectionManager conMan = new PoolingClientConnectionManager( SchemeRegistryFactory.createDefault() );
        conMan.setMaxTotal(200);
        conMan.setDefaultMaxPerRoute(200);

        client = new DefaultHttpClient(conMan);

        //The following parameter configurations are not
        //neccessary for this example, but they show how
        //to further tweak the HttpClient
        HttpParams params = client.getParams();
        HttpConnectionParams.setConnectionTimeout(params, 20000);
        HttpConnectionParams.setSoTimeout(params, 15000);
    }


    //This method can be called concurrently by several threads
    private InputStream getResource(String uri) {
        try {
            HttpGet method = new HttpGet(uri);
            HttpResponse httpResponse = client.execute(method);
            int statusCode = httpResponse.getStatusLine().getStatusCode();
            InputStream is = null;
            if (HttpStatus.SC_OK == statusCode) {
                logger.debug("200 OK Amazon request");
                is = httpResponse.getEntity().getContent();
            } else {
                logger.debug("Something went wrong, statusCode is {}",
                        statusCode);
                 EntityUtils.consume(httpResponse.getEntity());
            }
            return is;
        } catch (Exception e) {
            logger.error("Something went terribly wrong", e);
            throw new RuntimeException(e);
        }
    }
}


답변

이것은 자주 묻는 질문입니다. BalusC의 응답이 정확합니다. HttpReponseException을 포착 하고 HttpResponseException을 호출하십시오. 응답 . 무시 (). 오류 메시지를 읽어야하는 경우 응답을 사용하십시오. 응답 내용 유형을 모르는 경우 parseAsString (), 내용 유형을 알고있는 경우 응답을 사용합니다. parseAs (MyType.class).

에서 간단한 코드 조각 YouTubeSample.java 에서 유튜브 – jsonc 샘플 (일반적으로 비록 당신이 실제 응용 프로그램에서 스마트 무언가를 할 수 있습니다)

  } catch (HttpResponseException e) {
    System.err.println(e.response.parseAsString());
  }

전체 공개 : 저는 google-api-java-client 프로젝트 의 소유자입니다 .


답변

Response내 단위 테스트에서 jax-rs (resteasy) 개체 와 동일한 문제가 발생했습니다 . 나는에 대한 호출을 통해이 문제를 해결 response.releaseConnection();
releaseConnection () – 방법 만 RESTEasy가의에 ClientResponse객체, 내가로부터 캐스트를 추가했다, 그래서 ResponseClientResponse.


답변

이 시도

HttpResponse response = Client.execute(httpGet);
response.getEntity().consumeContent();
StatusLine statusLine = response.getStatusLine();
int statusCode = statusLine.getStatusCode();
if (statusCode == 200) {
        //task
    Log.i("Connection", "OK");
    }else{
     Log.i("Connection", "Down");
    }


답변

좋아, 비슷한 문제가 있습니다. 모든 솔루션이 작동하지 않고 일부 장치에서 테스트했으며 문제는 장치의 날짜였으며 2013 대신 2011이었습니다. 도움이 될 수 있는지 확인하십시오.