使用HttpRequest.execute()的exception:SingleClientConnManager的使用无效:仍然分配连接

我正在使用谷歌API客户端Java 1.2.1-alpha来执行一个POST请求,并且当我执行()HttpRequest时得到以下的堆栈跟踪。

它发生之后立即捕捉并忽略从以前的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构buildtesting框架时,我遇到了类似的问题。 我不得不从我的客户端向Servelet创build多个请求,但是它在执行时给出了相同的exception。

我在http://foo.jasonhudgins.com/2010/03/http-connections-revisited.htmlfind了一个替代scheme

您也可以使用以下方法来实例化您的客户端。

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

类似的exception消息(至less从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交互时,可能会发生此exception。

你怎么能让一个4.2的DefaultHttpClient实例线程安全( 线程安全的意义上,两个或两个以上的线程可以与之交互,而不会超出错误信息)? 使用org.apache.http.impl.conn.PoolingClientConnectionManager的forms为DefaultHttpClient提供连接池ClientConnectionManager

 /* 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 ()如果你不知道响应内容types,否则如果你知道内容types使用响应。 parseAs (MyType.class)。

youtube-jsonc-sample中的一个简单的YouTubeSample.java代码片段(虽然通常你会想在真实的应用程序中做一些更聪明的事情):

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

完全披露:我是google-api-java-client项目的所有者。

我在unit testing中遇到了与jax-rs(resteasy) Response对象相同的问题。 我通过调用response.releaseConnection();来解决这个问题response.releaseConnection(); releaseConnection() – 方法只在客户端的ResponseResponse对象上,所以我不得不添加从ResponseClientResponse的强制转换。

好的,我有类似的问题,所有这些解决scheme不工作,我在某些设备上testing,问题是设备中的date,这是2011年,而不是2013年,检查也可以帮助。

尝试这个

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

像这样读取InputStream:

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