Exceção usando httprequest.execute (): uso inválido de singleclientconnmanager: conexão ainda alocada

StackOverflow https://stackoverflow.com/questions/4612573

Pergunta

Estou usando o google-api-client-java 1.2.1-alfa para executar uma solicitação de postagem e estou obtendo o seguinte Stacktrace quando executar () o httprequest.

Isso acontece imediatamente depois de pegar e ignorar um erro 403 de uma postagem anterior para o mesmo URL e reutilizar o transporte para a solicitação subsequente. (Está em um loop inserindo várias entradas na mesma alimentação de átomos).

Há algo que eu deveria fazer para 'limpar' depois de um 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)

Por que o código abaixo de mim estaria tentando adquirir um novo conexão?

Foi útil?

Solução

Você precisa consumir o corpo de resposta antes de reutilizar a conexão para outra solicitação. Você não deve apenas ler o status da resposta, mas também leia a resposta InputStream Totalmente para o último byte pelo qual você apenas ignora os bytes de leitura.

Outras dicas

Eu estava enfrentando um problema semelhante ao usar o httpclient com o Jetty para criar uma estrutura de teste. Eu tive que criar várias solicitações para o Servelet do meu cliente, mas estava dando a mesma exceção quando executado.

Eu encontrei uma alternativa em http://foo.jasonhudgins.com/2010/03/http-connections-revisited.html

Você também pode usar este método a seguir para instanciar seu cliente.

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

Uma mensagem de exceção semelhante (já que pelo menos o 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.

Esta exceção pode acontecer quando dois ou mais threads interagem com um único org.apache.http.impl.client.DefaultHttpClient.

Como você pode fazer um 4.2 DefaultHttpClient instância threadSafe (discussão segura No sentido de que dois ou mais threads podem interagir com ele sem receber a mensagem de erro acima)? Providenciar DefaultHttpClient com um pool de conexão ClientConnectionManager na forma de 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);
        }
    }
}

Esta é uma pergunta frequente. A resposta de Balusc está correta. Por favor, pegue HttpreponseException, e ligue para HTTPRESPOnseException.resposta.ignorar(). Se você precisar ler a mensagem de erro, use a resposta.Parseasstring() Se você não conhece o tipo de conteúdo de resposta, se você souber o tipo de conteúdo, use a resposta.Parseas(Mytype.class).

Um snippet de código simples de Youtubesample.java dentro YouTube-JSONC-Sple (Embora geralmente você queira fazer algo mais inteligente em um aplicativo real):

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

Divulgação completa: eu sou um proprietário do Google-api-java-client projeto.

Eu tive o mesmo problema com um Jax-rs (Restasy) Response Objeto nos meus testes de unidade. Eu resolvi isso com uma chamada para response.releaseConnection();O método releaseConnection ()-está apenas no Restasy ClientResponse objeto, então eu tive que adicionar um elenco de Response para ClientResponse.

Tente isso

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

OK, eu tenho um problema semelhante, toda aquela solução não funciona, testei em algum dispositivo, o problema foi a data do dispositivo, em 2011, em 2013, verifique também isso pode ajudar.

Leia o InputStream como este:

if( response.getStatusLine().getStatusCode() == 200 ) {
    HttpEntity entity = response.getEntity();
    InputStream content = entity.getContent();
    try {
        sb = new StringBuilder();
        BufferedReader bufferedReader = new BufferedReader( new InputStreamReader( content ), 8 );
        String line;
        while( ( line = bufferedReader.readLine() ) != null ) {
            sb.append( line );
        }
        bufferedReader.close();
        content.close();
    } catch( Exception ex ) {
        Log.e( "statusCode", ex.getMessage() + "" );
    }
}

basta consumir a resposta como abaixo, que resolverá o problema

response.getEntity().consumeContent();
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top