Exceção usando httprequest.execute (): uso inválido de singleclientconnmanager: conexão ainda alocada
-
26-09-2019 - |
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?
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();