82

我正在使用 google-api-client-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)

为什么我下面的代码会尝试获取连接?

4

9 回答 9

83

您需要先使用响应正文,然后才能将连接重用于另一个请求。您不仅应该读取响应状态,还应该将响应InputStream完全读取到最后一个字节,从而忽略读取的字节。

于 2011-01-07T01:28:43.677 回答
42

在使用 HttpClient 和 Jetty 构建测试框架时,我遇到了类似的问题。我必须从我的客户端创建多个对 Servelet 的请求,但它在执行时给出了相同的异常。

我在http://foo.jasonhudgins.com/2010/03/http-connections-revisited.html找到了一个替代方案

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

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;
}
于 2011-07-18T18:36:22.453 回答
9

类似的异常消息(至少从 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.

您如何使 4.2DefaultHttpClient实例线程安全(线程安全,即两个或多个线程可以与其交互而不会出现上述错误消息)?以!的形式提供DefaultHttpClient连接池ClientConnectionManagerorg.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);
        }
    }
}
于 2013-02-07T22:50:58.383 回答
8

这是一个经常被问到的问题。BalusC 的回答是正确的。请捕获HttpReponseException并调用 HttpResponseException。回应忽略()。如果您需要阅读错误消息,请使用响应。parseAsString () 如果你不知道响应内容类型,否则如果你知道内容类型使用响应。parseAs (MyType.class)。

youtube-jsonc-sample中 YouTubeSample.java中的一个简单代码片段(尽管通常您希望在实际应用程序中做一些更智能的事情):

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

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

于 2011-01-10T14:44:08.427 回答
3

Response在我的单元测试中,我遇到了与 jax-rs(resteasy)对象相同的问题。我通过调用response.releaseConnection(); releaseConnection()-Method 解决了这个问题,它只在 resteasyClientResponse对象上,所以我不得不添加一个从Responseto的转换ClientResponse

于 2012-10-18T09:00:01.883 回答
1

试试这个

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");
    }
于 2014-06-10T06:02:17.710 回答
0

好的,我有类似的问题,所有这些解决方案都不起作用,我在某些设备上进行了测试,问题是设备中的日期,它是 2011 年而不是 2013 年,检查这也可以提供帮助。

于 2013-02-08T11:42:17.380 回答
0

像这样读取 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() + "" );
    }
}
于 2014-08-24T14:26:37.500 回答
0

只需使用下面的响应,即可解决问题

response.getEntity().consumeContent();
于 2019-06-24T14:47:08.990 回答