HttpRequest.execute () का उपयोग करके अपवाद: SingleClientConnManager का अवैध उपयोग: कनेक्शन अभी भी आबंटित है


81

मैं एक POST अनुरोध को निष्पादित करने के लिए google-api-client-java 1.2.1-Alpha का उपयोग कर रहा हूं, और जब मैं 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)

मेरे नीचे का कोड नया कनेक्शन प्राप्त करने का प्रयास क्यों करेगा ?


यह अभी भी संस्करण 1.11.0-बीटा: /
sjngm

5
प्रतिक्रियाओं का उपभोग करने और अभी भी चेतावनियों को प्राप्त करने के बाद यहां पहुंचने वाले किसी भी व्यक्ति के लाभ के लिए - मुझे यहाँ सही उत्तर मिला: tech.chitgoks.com/2011/05/05/…
Steelight

@Steelight - tech.chitgoks.com दृष्टिकोण का उपयोग करके मेरी समस्या का समाधान किया गया।
काले स्वीनी

जवाबों:


82

किसी अन्य अनुरोध के लिए कनेक्शन का पुन: उपयोग करने से पहले आपको प्रतिक्रिया शरीर का उपभोग करना होगा। आपको न केवल प्रतिक्रिया की स्थिति को पढ़ना चाहिए, बल्कि InputStreamअंतिम बाइट के लिए पूरी तरह से प्रतिक्रिया पढ़ें, जिससे आप केवल पढ़ने के बाइट्स को अनदेखा करते हैं।


1
वह यह था! के मामले में google-api-java-client, इसका मतलब यह था कि IOExceptionफेंकने वाले को पकड़ना HttpResponse.execute(), उसका परीक्षण / कास्टिंग करना HttpResponseException, responseसदस्य तक पहुंचना , और फिर उस paraseAsString()पर आक्रमण करना। (जो किसी भी तरह उपयोगी जानकारी निकला: -)
डेविड बैल

5
सामग्री को छोड़ने के लिए एक HttpEntity.consumeContent () विधि भी है।
ग्रेजेगॉर एडम हंकीविज़

3
EntityUtils.consume (एंटिटी) - कंसेंट कंटेंट अब अपग्रेड हो गया है।
डेविड कार्बोनी

बस ध्यान दें कि Google Http जावा क्लाइंट के हाल के संस्करणों के रूप में (कम से कम 1.16, लेकिन संभवतः पहले), कॉलिंग HttpRequest.execute()स्वचालित रूप से इन संसाधनों को साफ कर देगी यदि विधि किसी HttpResponseऑब्जेक्ट को वापस करने में विफल रहती है । इसके अलावा, HttpResponseअब HTTPDoc response.disconnect()HTTP प्रतिक्रिया (एक finallyब्लॉक में) की सामग्री को पूरी तरह से नहीं पढ़ने के मामले में कॉल करने की सिफारिश करता है ।
डेविड बुलॉक

RestEasy 3.0.4 के साथ एक ही समस्या जो आंतरिक रूप से Apache-httpclient 4.2.1 के BasicClientConnectionManager का उपयोग करती है। साभार @BalusC इसके अलावा, मैंने कभी भी स्ट्रीम को पूरी तरह से पढ़ने के बारे में कुछ भी नहीं पढ़ा, जहां इन नुकसानों के बारे में पता होना चाहिए? (दस्तावेज़ीकरण, स्रोत कोड के अलावा)
एलेरिया

42

टेस्ट फ्रेमवर्क बनाने के लिए जेट्टी के साथ HttpClient का उपयोग करते समय मुझे एक समान समस्या का सामना करना पड़ रहा था। मुझे अपने क्लाइंट से सेरविलेट में कई अनुरोध बनाने थे, लेकिन निष्पादित होने पर यह एक ही अपवाद दे रहा था।

मुझे 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;
}

धन्यवाद, बहुत अच्छा काम किया। हालाँकि मैं दो DefaultHttpClients बनाने की आवश्यकता पर उत्सुक हूं
htafoya

2
वह स्वयं स्क्रैप्ट से निर्माण करने के बजाय डिफ़ॉल्ट HttpParams (क्लाइंट से प्राप्त करता है) का उपयोग करता है।
मार्सिन गिल

इससे मेरी समस्या हल हो गई, लेकिन क्या Android एप्लिकेशन में इसका उपयोग करना ठीक है।
मनीष

दिलचस्प बात यह है कि यह आंशिक रूप से मेरे लिए काम करता है, शेष कोड को निष्पादित करने से रोकना समाप्त करता है जब मैं कई HTTP अनुरोधों को लूप में करता हूं और प्रतिक्रियाओं का उपभोग नहीं करता हूं। और कोई विफलता या तो, मैं यह देखने के लिए बहुत लंबा इंतजार नहीं किया कि क्या कोई टाइमआउट त्रुटि होती है। इसलिए इसके बजाय मैं प्रत्येक अनुरोध के लिए नए DefaultHttpClients को आवंटित करने का मार्ग गया और मेरे लिए काम किया, क्योंकि मैं बहुत लंबे समय तक लूप नहीं चलाता।
डेविड

9

एक समान अपवाद संदेश (चूंकि कम से कम अपाचे जारटाटा कॉमन्स HTTP क्लाइंट 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उदाहरण थ्रेडसेफ़ कैसे बना सकते हैं ( थ्रेडसेफ़ इस अर्थ में कि दो या दो से अधिक धागे बिना किसी त्रुटि के ऊपर से बातचीत कर सकते हैं)? प्रदान 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);
        }
    }
}

8

यह अक्सर पूछे जाने वाला प्रश्न है। BalusC की प्रतिक्रिया सही है। कृपया HttpReponseException को पकड़ें , और HttpResponseException को कॉल करें। प्रतिक्रियाउपेक्षा ()। यदि आपको त्रुटि संदेश पढ़ने की आवश्यकता है, तो प्रतिक्रिया का उपयोग करें। parseAsString () यदि आप प्रतिक्रिया सामग्री प्रकार नहीं जानते हैं, तो यदि आप सामग्री प्रकार उपयोग प्रतिक्रिया जानते हैं। parseAs (MyType.class)।

YouTube-jsonc- नमूने में YouTubeSample.java का एक सरल कोड स्निपेट (हालांकि आमतौर पर आप वास्तविक एप्लिकेशन में कुछ स्मार्ट करना चाहेंगे):

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

पूर्ण प्रकटीकरण: मैं google-api-java-client परियोजना का मालिक हूं ।


15
क्या यह तथ्य नहीं है कि यह अक्सर पूछा जाने वाला प्रश्न है कि आपके पुस्तकालय डिजाइन में उपयोगिता की समस्या है?
विवेक

@ दान या शायद http स्टैक में ही;)
krosenvold

3

Responseमेरी इकाई परीक्षणों में एक jax-rs (resteasy) ऑब्जेक्ट के साथ एक ही मुद्दा था । मैं करने के लिए एक फोन के साथ इस हल response.releaseConnection(); releaseConnection () - पद्धति केवल resteasy पर है ClientResponseवस्तु, इसलिए मैं से एक डाली जोड़ने के लिए किया था Responseके लिए ClientResponse


जिससे मेरा दिन बच गया! मेरे मामले में मुझे इसे और संकीर्ण करने के लिए org.jboss.resteasy.client.jaxrs.internal.ClientResponse पर कास्ट करना पड़ा।
user2081279

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

0

ठीक है, मेरे पास समान समस्या है, उन सभी समाधानों से काम नहीं होता है, मैंने किसी डिवाइस पर परीक्षण किया है, समस्या डिवाइस में तारीख थी, यह 2013 के बजाय 2011 था, यह भी जाँचें इससे मदद मिल सकती है।


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

0

बस नीचे की तरह प्रतिक्रिया का उपभोग करें, इससे समस्या हल हो जाएगी

response.getEntity().consumeContent();
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.