web-dev-qa-db-fra.com

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

J'utilise google-api-client-Java 1.2.1-alpha pour exécuter une demande POST, et j'obtiens le stacktrace suivant lorsque j'exécute () le HttpRequest. 

Cela se produit immédiatement après que j'attrape et ignore une erreur 403 d'un précédent POST sur la même URL et que je réutilise le transport pour la requête suivante. (Il s’agit d’une boucle qui insère plusieurs entrées dans le même flux ATOM).

Y a-t-il quelque chose que je devrais faire pour "nettoyer" après une 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 code ci-dessous tente-t-il d’acquérir une connexion new ?

78
David Bullock

Vous devez utiliser le corps de la réponse avant de pouvoir réutiliser la connexion pour une autre demande. Vous devez non seulement lire l'état de la réponse, mais également lire la réponse InputStream au dernier octet, ce qui vous permet d'ignorer les octets lus.

80
BalusC

J'étais confronté à un problème similaire lors de l'utilisation de HttpClient avec Jetty pour créer un cadre de test. Je devais créer plusieurs requêtes sur le Servelet à partir de mon client, mais cela donnait la même exception lors de son exécution.

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

Vous pouvez également utiliser cette méthode 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
Ujjwal Wadhawan

Un message d’exception similaire (car au moins Apache Jarkata Commons HTTP Client 4.2) est le suivant:

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 ou plusieurs threads interagissent avec un seul org.Apache.http.impl.client.DefaultHttpClient.

Comment pouvez-vous créer une instance 4.2 DefaultHttpClient threadsafe ( threadsafe dans le sens où deux threads ou plus peuvent interagir avec elle sans obtenir le message d'erreur précédent)? Fournissez à DefaultHttpClient un pool de connexions 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
Abdull

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

Un simple extrait de code de YouTubeSample.Java dans youtube-jsonc-sample (bien que vous souhaitiez généralement 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
Yaniv Inbar

J'ai eu le même problème avec un objet jax-rs (Resteasy) Response dans mes tests unitaires. J'ai résolu ce problème en appelant response.releaseConnection(); La méthode releaseConnection () - ne concerne que l'objet resteasy ClientResponse. J'ai donc dû ajouter un transtypage de Response à ClientResponse.

3
markus

juste consommer la réponse comme ci-dessous, cela va résoudre le problème

response.getEntity().consumeContent();
0
Mohammed Rafeeq

Essaye ça

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

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

0
marko

Lisez le InputStream 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
lucasddaniel