私はgoogle-api-client-Java 1.2.1-alphaを使用してPOST要求を実行し、HttpRequestをexecute()するときに次のスタックトレースを取得しています。
前の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)
下のコードがnew接続を取得しようとするのはなぜですか?
別の要求に接続を再利用する前に、応答本文を消費する必要があります。応答ステータスを読み取るだけでなく、応答InputStream
を最後のバイトまで完全に読み取り、読み取りバイトを無視する必要があります。
JettyでHttpClientを使用してテストフレームワークを構築するときに、同様の問題に直面していました。クライアントから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;
}
同様の例外メッセージ(少なくとも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.
この例外は、2つ以上のスレッドが単一のorg.Apache.http.impl.client.DefaultHttpClient
と対話するときに発生する可能性があります。
4.2 DefaultHttpClient
インスタンスをスレッドセーフ(threadsafeにするにはどうすればよいですか?メッセージ)? DefaultHttpClient
にorg.Apache.http.impl.conn.PoolingClientConnectionManager
の形式で接続プール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を呼び出してください。 response . ignore ()。エラーメッセージを読む必要がある場合は、応答を使用してください。応答コンテンツタイプがわからない場合はresponse . parseAsString ()、そうでない場合は応答を使用するコンテンツタイプがわかっている場合 parseAs (MyType.class)。
YouTubeSample.Java in youtube-jsonc-sample からの簡単なコードスニペット(通常、実際のアプリケーションではもっとスマートにしたいでしょう):
} catch (HttpResponseException e) {
System.err.println(e.response.parseAsString());
}
完全な開示:私は google-api-Java-client プロジェクトの所有者です。
ユニットテストで、jax-rs(resteasy)Response
オブジェクトでも同じ問題が発生しました。 response.releaseConnection();
への呼び出しでこれを解決しました。releaseConnection()メソッドは、resteasyのClientResponse
オブジェクトのみにあるため、Response
からClientResponse
へのキャストを追加する必要がありました。
これを試して
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");
}
以下のような応答を消費するだけで問題が解決します
response.getEntity().consumeContent();
OK、私は同様の問題を抱えています、それらのすべての解決策は機能しません、いくつかのデバイスでテストしました、問題はデバイスの日付でした、それは2013ではなく2011でした、これも助けることができます。
次のように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() + "" );
}
}