2009-09-17 10 views
28

मुझे लगता है कि एक लाइब्रेरी जिसका मैं उपयोग कर रहा हूं (साइनपॉस्ट 1.1-एसएनएपीएसएचओटी), एंड्रॉइड 1.5 पर एक अनोखी समस्या में चल रहा है, रिमोट सर्वर से लगातार दो कनेक्शन बनाता है। दूसरा कनेक्शन हमेशा एक HttpURLConnection.getResponseCode() की -1HttpURLConnection.getResponseCode() दूसरे आवेषण पर रिटर्न -1

यहाँ एक testcase कि समस्या को उजागर करता है के साथ विफल:

// BROKEN 
public void testDefaultOAuthConsumerAndroidBug() throws Exception { 
    for (int i = 0; i < 2; ++i) { 
     final HttpURLConnection c = (HttpURLConnection) new URL("https://api.tripit.com/oauth/request_token").openConnection(); 
     final DefaultOAuthConsumer consumer = new DefaultOAuthConsumer(api_key, api_secret, SignatureMethod.HMAC_SHA1); 
     consumer.sign(c);        // This line... 
     final InputStream is = c.getInputStream(); 
     while(is.read() >= 0) ;      // ... in combination with this line causes responseCode -1 for i==1 when using api.tripit.com but not mail.google.com 
     assertTrue(c.getResponseCode() > 0); 
    } 
} 

असल में, अगर मैं अनुरोध करें और फिर पूरे इनपुट धारा उपभोग करते हैं, अगले अनुरोध के साथ असफल हो जायेगी -1 का परिणाम कोड अगर मैं इनपुट स्ट्रीम से सिर्फ एक वर्ण पढ़ता हूं तो विफलता प्रतीत नहीं होती है।

ध्यान दें कि यह किसी भी यूआरएल के लिए नहीं होता है - उपर्युक्त उपरोक्त विशिष्ट यूआरएल।

इसके अलावा, अगर मैं HttpURLConnection के बजाय HttpClient उपयोग भी कर, सब कुछ ठीक काम करता है:

// WORKS 
public void testCommonsHttpOAuthConsumerAndroidBug() throws Exception { 
    for (int i = 0; i < 2; ++i) { 
     final HttpGet c = new HttpGet("https://api.tripit.com/oauth/request_token"); 
     final CommonsHttpOAuthConsumer consumer = new CommonsHttpOAuthConsumer(api_key, api_secret, SignatureMethod.HMAC_SHA1); 
     consumer.sign(c); 
     final HttpResponse response = new DefaultHttpClient().execute(c); 
     final InputStream is = response.getEntity().getContent(); 
     while(is.read() >= 0) ; 
     assertTrue(response.getStatusLine().getStatusCode() == 200); 
    } 
} 

मैं क्या एक समान समस्या कहीं और हो रहा है के लिए references पाया है, लेकिन अभी तक कोई समाधान। यदि वे वास्तव में एक ही समस्या हैं, तो समस्या शायद साइनपॉस्ट के साथ नहीं है क्योंकि अन्य संदर्भ इसका कोई संदर्भ नहीं देते हैं।

कोई भी विचार?

उत्तर

28

अगर यह मदद करता है देखने के लिए,

http.keepAlive=false 

मैं इसी तरह की समस्याओं को देखा जब सर्वर प्रतिक्रिया सिंक्रनाइज़ेशन से बाहर हो जाता है UrlConnection और क्लाइंट/सर्वर से समझा नहीं गया है यह गुण सेट करने का प्रयास करें।

यदि यह आपकी समस्या हल करता है, तो आपको प्रतिक्रिया के बारे में विशेष रूप से देखने के लिए एक HTTP ट्रेस प्राप्त करना होगा।

संपादित करें: यह परिवर्तन सिर्फ मेरे संदेह की पुष्टि करता है। यह आपकी समस्या का समाधान नहीं करता है। यह सिर्फ लक्षण छुपाता है।

यदि पहले अनुरोध की प्रतिक्रिया 200 है, तो हमें एक ट्रेस की आवश्यकता है। मैं आमतौर पर टीसीपी ट्रेस प्राप्त करने के लिए एथेरियल/वायर्सहार्क का उपयोग करता हूं।

यदि आपकी पहली प्रतिक्रिया 200 नहीं है, तो मुझे आपके कोड में कोई समस्या दिखाई देती है। ओएथ के साथ, त्रुटि प्रतिक्रिया (401) वास्तव में डेटा लौटाती है, जिसमें आपको डीबग करने में मदद करने के लिए समस्या एडवाइस, हस्ताक्षर बेस स्ट्रिंग इत्यादि शामिल हैं। आपको त्रुटि स्ट्रीम से सब कुछ पढ़ने की जरूरत है। अन्यथा, यह अगले कनेक्शन को भ्रमित करने जा रहा है और यह -1 का कारण है। उदाहरण के बाद पता चलता है आप कैसे त्रुटियों को सही ढंग से संभाल करने के लिए,

public static String get(String url) throws IOException { 

    ByteArrayOutputStream os = new ByteArrayOutputStream(); 
    URLConnection conn=null; 
    byte[] buf = new byte[4096]; 

    try { 
     URL a = new URL(url); 
     conn = a.openConnection(); 
     InputStream is = conn.getInputStream(); 
     int ret = 0; 
     while ((ret = is.read(buf)) > 0) { 
      os.write(buf, 0, ret); 
     } 
     // close the inputstream 
     is.close(); 
     return new String(os.toByteArray()); 
    } catch (IOException e) { 
     try { 
      int respCode = ((HttpURLConnection)conn).getResponseCode(); 
      InputStream es = ((HttpURLConnection)conn).getErrorStream(); 
      int ret = 0; 
      // read the response body 
      while ((ret = es.read(buf)) > 0) { 
       os.write(buf, 0, ret); 
      } 
      // close the errorstream 
      es.close(); 
      return "Error response " + respCode + ": " + 
       new String(os.toByteArray()); 
     } catch(IOException ex) { 
      throw ex; 
     } 
    } 
} 
+4

दिलचस्प। टेस्टकेस की शुरुआत में 'System.setProperty (" http.keepAlive "," false ") जोड़ना पूरी तरह से समस्या हल करता है। http ट्रेस कैसे करें पर कोई सुझाव? क्या मुझे लॉगिंग प्रॉक्सी का उपयोग करने की ज़रूरत है, या क्या मैं क्लाइंट पर सीधे कुछ कर सकता हूं? – emmby

+0

मेरा संपादन देखें .............. –

+1

पुष्टि की कि यह एक एंड्रॉइड बग है, और हम इसे यहां ट्रैक कर रहे हैं: http://code.google.com/p/android/issues/ विस्तार? आईडी = 7786 –

0

क्या आप सत्यापित कर सकते हैं कि प्रतिक्रिया पढ़ने से पहले कनेक्शन बंद नहीं हो रहा है? हो सकता है कि HttpClient तुरंत प्रतिक्रिया कोड का विश्लेषण करता है, और भविष्य के प्रश्नों के लिए इसे बचाता है, हालांकि कनेक्शन बंद होने के बाद HttpURLConnection वापस आ सकता है?

10

मैं एक ही समस्या आई थी जब मैं इसे बंद करने और एक दूसरे कनेक्शन खोलने से पहले InputStream से सभी डेटा में पढ़ा नहीं था। इसे System.setProperty("http.keepAlive", "false"); के साथ या बस बस लूपिंग के साथ भी तय किया गया जब तक कि मैंने शेष इनपुटस्ट्रीम को पढ़ नहीं लिया।

आपकी समस्या से पूरी तरह से संबंधित नहीं है, लेकिन उम्मीद है कि यह किसी अन्य समस्या को किसी अन्य समस्या से मदद करता है।

5

गूगल एक सुरुचिपूर्ण समाधान का यह केवल Froyo करने से पहले हो रहा है के बाद से प्रदान की:

private void disableConnectionReuseIfNecessary() { 
    // HTTP connection reuse which was buggy pre-froyo 
    if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) { 
     System.setProperty("http.keepAlive", "false"); 
    } 
} 

सी एफ http://android-developers.blogspot.ca/2011/09/androids-http-clients.html

+0

पूरी तरह से काम करते हैं। मेरे लिए यह चीजें स्ट्रिप का उपयोग करते हुए एपीआई 4.1.1 में हुईं। –

2

या, आप कनेक्शन (HttpUrlConnection) में HTTP हेडर सेट कर सकते हैं:

conn.setRequestProperty("Connection", "close"); 
संबंधित मुद्दे