Exception utilisant HttpRequest.execute (): utilisation non valide de SingleClientConnManager: connexion toujours allouée

J'utilise google-api-client-java 1.2.1-alpha pour exécuter une requête POST, et j'obtiens la stacktrace suivante lorsque j'exécute () le HttpRequest.

Cela se produit immédiatement après avoir attrapé et ignoré une erreur 403 d'un POST précédent vers la même URL, et réutilisé le transport pour la requête suivante. (C'est dans une boucle en insérant plusieurs entrées dans le même flux ATOM).

Y a-t-il quelque chose que je devrais faire pour 'nettoyer' après un 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)

Pourquoi le le code ci-dessous essaie d'acquérir une nouvelle connexion ?

78
demandé sur BalusC 2011-01-06 09:57:20

8 réponses

Vous devez utiliser le corps de la réponse avant de pouvoir réutiliser la connexion pour une autre requête. Vous ne devriez pas seulement lire l'état de la réponse, mais lire la réponse InputStream complètement au dernier octet par lequel vous ignorez simplement les octets lus.

80
répondu BalusC 2011-01-07 01:28:43

J'étais confronté à un problème similaire lors de l'utilisation de HttpClient avec Jetty pour construire un framework de test. J'ai dû créer plusieurs requêtes au Servelet de mon client, mais il donnait la même exception lorsqu'il était exécuté.

J'ai trouvé une alternative à http://foo.jasonhudgins.com/2010/03/http-connections-revisited.html

Vous pouvez également utiliser la méthode suivante pour instancier votre client.

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;
}
42
répondu Ujjwal Wadhawan 2011-07-18 18:36:22

Un message d'exception similaire (depuis au moins Apache Jarkata Commons HTTP client 4.2) est:

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

Cette exception peut se produire lorsque deux threads ou plus interagissent avec un seul org.apache.http.impl.client.DefaultHttpClient.

Comment Pouvez-vous créer une instance threadsafe 4.2 DefaultHttpClient (threadsafe dans le sens où deux threads ou plus peuvent interagir avec elle sans obtenir le message d'erreur ci-dessus)? Fournir DefaultHttpClient avec un pool de connexion ClientConnectionManager sous la forme 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);
        }
    }
}
9
répondu Abdull 2013-03-25 08:19:03

C'est une question souvent posée. La réponse de BalusC est correcte. Veuillez attraper HttpReponseException et appeler HttpResponseException.réponse.ignorer(). Si vous devez lire le message d'erreur, utilisez response.parseAsString() si vous ne connaissez pas le contenu de la réponse, sinon, si vous connaissez le type de contenu utiliser la réponse. parseAs (MyType.classe).

Un extrait de code simple de YouTubeSample.java dans youtube-jsonc-échantillon (bien que généralement vous voudrez faire quelque chose de plus intelligent dans une application réelle):

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

Divulgation complète: je suis propriétaire du projet google-api-java-client .

8
répondu Yaniv Inbar 2011-01-10 14:44:08

J'ai eu le même problème avec un objet JAX-rs (resteasy) Response dans mes tests unitaires. J'ai résolu cela avec un appel à response.releaseConnection(); La méthode releaseConnection () est uniquement sur l'objet resteasy ClientResponse, donc j'ai dû ajouter un cast de Response à ClientResponse.

2
répondu markus 2012-10-18 09:00:01

Ok, j'ai un problème similaire, toutes ces solutions ne fonctionnent pas, j'ai testé sur un appareil, le problème était la date dans l'appareil, c'était 2011 au lieu de 2013, vérifiez aussi cela peut aider.

0
répondu marko 2013-02-08 11:42:17

Essayez ceci

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");
    }
0
répondu Silambarasan Poonguti 2014-06-10 06:02:17

Lisez le flux D'entrée comme ceci:

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() + "" );
    }
}
0
répondu lucasddaniel 2015-03-12 06:18:38