استثناء باستخدام httprequest.execute (): استخدام غير صالح لـ SingleClientConnmanager: لا يزال الاتصال مخصصًا

StackOverflow https://stackoverflow.com/questions/4612573

سؤال

أنا أستخدم Google-API-Client-Java 1.2.1-alpha لتنفيذ طلب نشر ، وأحصل على stacktrace التالية عندما أقوم بتنفيذ () httprequest.

يحدث ذلك فورًا بعد التقاط وتجاهل خطأ 403 من منشور سابق إلى عنوان URL نفسه ، وإعادة استخدام النقل للطلب اللاحق. (إنه في حلقة إدراج إدخالات متعددة لنفس تغذية الذرة).

هل هناك شيء يجب أن أفعله "للتنظيف" بعد 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 بالكامل إلى آخر بايت حيث تتجاهل بايت القراءة.

نصائح أخرى

كنت أواجه مشكلة مماثلة عند استخدام 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.

يمكن أن يحدث هذا الاستثناء عندما يتفاعل اثنين أو أكثر من الخيوط مع واحد org.apache.http.impl.client.DefaultHttpClient.

كيف يمكنك صنع 4.2 DefaultHttpClient مثيل ThreadSafe (المواضيع بمعنى أن خيطين أو أكثر يمكن أن يتفاعل معها دون الحصول على رسالة خطأ أعلاه)؟ تزود DefaultHttpClient مع تجميع الاتصال ClientConnectionManager في شكل 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);
        }
    }
}

هذا سؤال في كثير من الأحيان. استجابة Balusc صحيحة. الرجاء التقاط httpreponsexception, ، واتصل httpresponsexception.استجابة.يتجاهل(). إذا كنت بحاجة إلى قراءة رسالة الخطأ ، فاستخدم الاستجابة.parseasstring() إذا كنت لا تعرف نوع محتوى الاستجابة ، وإلا إذا كنت تعرف استجابة نوع المحتوى استخدم.parseas(mytype.class).

مقتطف رمز بسيط من youtubesample.java في YouTube-Jsonc-Sample (على الرغم من أنك ستحتاج عادةً إلى القيام بشيء أكثر ذكاءً في تطبيق حقيقي):

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

الكشف الكامل: أنا مالك Google-API-Java-Client مشروع.

واجهت نفس المشكلة مع Jax-RS (Resteasy) Response كائن في اختبارات وحدتي. لقد حللت هذا مع دعوة إلى response.releaseConnection();طريقة RELEASECONNECTION ()-هي فقط على الباقي 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");
    }

حسنًا ، لدي مشكلة مماثلة ، كل هذه الحلول التي لا تعمل ، لقد اختبرت على بعض الأجهزة ، كانت المشكلة في الجهاز ، وكان عام 2011 بدلاً من عام 2013 ، تحقق أيضًا من أن هذا يمكن أن يساعد.

اقرأ 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() + "" );
    }
}

فقط استهلك الاستجابة كما هو أدناه ، وهذا سيحل المشكلة

response.getEntity().consumeContent();
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top