يقوم HttpURLConnection.getResponseCode() بإرجاع -1 عند الاستدعاء الثاني

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

سؤال

يبدو أنني أواجه مشكلة غريبة على Android 1.5 عندما تقوم المكتبة التي أستخدمها (signpost 1.1-SNAPSHOT) بإجراء اتصالين متتاليين بخادم بعيد.يفشل الاتصال الثاني دائمًا مع a HttpURLConnection.getResponseCode() ل -1

إليك حالة اختبار تكشف المشكلة:

// 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.لا يبدو أن الفشل يحدث إذا قرأت حرفًا واحدًا فقط من دفق الإدخال.

لاحظ أن هذا لا يحدث لأي عنوان URL - فقط عناوين URL محددة مثل العنوان أعلاه.

أيضًا، إذا قمت بالتبديل إلى استخدام HttpClient بدلاً من HttpURLConnection، فسيعمل كل شيء بشكل جيد:

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

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

أيه أفكار؟

هل كانت مفيدة؟

المحلول

حاول تعيين هذه الخاصية لمعرفة ما إذا كانت مفيدة،

http.keepAlive=false

لقد رأيت مشكلات مماثلة عندما لا يفهم UrlConnection استجابة الخادم ويخرج العميل/الخادم من المزامنة.

إذا أدى هذا إلى حل مشكلتك، فيجب عليك الحصول على تتبع HTTP لمعرفة ما يميز الاستجابة بالضبط.

يحرر:هذا التغيير يؤكد فقط شكوكي.لا يحل مشكلتك.إنه يخفي الأعراض فقط.

إذا كان الرد من الطلب الأول هو 200، فنحن بحاجة إلى تتبع.عادةً ما أستخدم Ethereal/Wireshark للحصول على تتبع TCP.

إذا لم تكن إجابتك الأولى 200، فأنا أرى مشكلة في الكود الخاص بك.باستخدام OAuth، تقوم استجابة الخطأ (401) فعليًا بإرجاع البيانات، والتي تتضمنProblemAdvice وSignature Base String وما إلى ذلك لمساعدتك في تصحيح الأخطاء.تحتاج إلى قراءة كل شيء من دفق الأخطاء.وإلا فإنه سوف يربك الاتصال التالي وهذا هو سبب -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;
        }
    }
}

نصائح أخرى

ولقد واجهت نفس المشكلة عندما لم يقرأ في كل البيانات من InputStream قبل إغلاقه وفتح اتصال ثاني. تم إصلاح أيضا إما مع System.setProperty("http.keepAlive", "false"); أو ببساطة مجرد حلقات حتى لقد قرأت بقية InputStream.

ولا علاقة تماما لمشكلتك، ولكن نأمل أن يساعد أي شخص آخر مع مشكلة مماثلة.

وقدمت جوجل يعد حل أنيق لأنه يحدث فقط قبل ل 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

وأو، يمكنك تعيين رأس HTTP في الاتصال (HttpUrlConnection):

conn.setRequestProperty("Connection", "close");

ويمكن التحقق من أن الاتصال لم يتم الحصول على أغلقت قبل الانتهاء من قراءة الرد؟ ربما HttpClient وإصلاحه يوزع رمز الاستجابة على الفور، وحفظه للاستعلامات في المستقبل، ولكن HttpURLConnection يمكن أن تكون عودته -1 بمجرد إغلاق الاتصال؟

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top