2009-09-17 7 views
28

Ich stoße auf ein seltsames Problem auf Android 1.5, wenn eine Bibliothek, die ich verwende (Wegweiser 1.1-SNAPSHOT), zwei aufeinanderfolgende Verbindungen zu einem Remote-Server. Die zweite Verbindung nicht immer mit einem HttpURLConnection.getResponseCode() von -1HttpURLConnection.getResponseCode() gibt -1 beim zweiten Aufruf zurück

Hier ist ein Testfall, der das Problem aussetzt:

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

Grundsätzlich, wenn ich den Antrag unterschreiben und verbrauchen dann den gesamten Eingangsstrom, wird die nächste Anforderung fehlschlagen mit ein Ergebniscode von -1. Der Fehler scheint nicht zu passieren, wenn ich gerade ein Zeichen aus dem Eingabestrom lese.

Beachten Sie, dass dies für keine URL - nur spezifische URLs wie die oben genannten geschieht.

Auch, wenn ich zur Verwendung von Httpclient statt HttpURLConnection wechseln, funktioniert alles einwandfrei:

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

ich gefunden habe references zu dem, was scheint an anderer Stelle ein ähnliches Problem zu sein, aber bisher keine Lösungen. Wenn es sich wirklich um das gleiche Problem handelt, liegt das Problem wahrscheinlich nicht beim Wegweiser, da die anderen Referenzen keinen Bezug darauf haben.

Irgendwelche Ideen?

Antwort

28

Versuchen Sie diese Eigenschaft, um zu sehen, ob es hilft,

http.keepAlive=false 

Ich sah ähnliche Probleme, wenn Server-Antwort nicht durch URLConnection und Client/Server verstanden wird nicht synchronisiert wird.

Wenn dies Ihr Problem löst, müssen Sie eine HTTP-Trace abrufen, um genau zu sehen, was das Besondere an der Antwort ist.

EDIT: Diese Änderung bestätigt nur meinen Verdacht. Es löst dein Problem nicht. Es verbirgt nur das Symptom.

Wenn die Antwort von der ersten Anfrage 200 ist, benötigen wir eine Ablaufverfolgung. Normalerweise benutze ich Ethereal/Wireshark, um den TCP-Trace zu erhalten.

Wenn Ihre erste Antwort nicht 200 ist, sehe ich ein Problem in Ihrem Code. Bei OAuth gibt die Fehlerantwort (401) tatsächlich Daten zurück, die ProblemAdvice, Signature Base String usw. enthalten, um Ihnen beim Debuggen zu helfen. Sie müssen alles aus dem Fehler-Stream lesen. Andernfalls wird die nächste Verbindung verwechselt, und das ist der Grund für -1. Beispiel folgenden sehen Sie, wie Fehler richtig zu handhaben,

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

Interessant. Das Hinzufügen von 'System.setProperty (" http.keepAlive "," false ")' am Anfang des Testfalls löst das Problem vollständig. Irgendwelche Vorschläge, wie man den HTTP-Trace macht? Muss ich einen Logging-Proxy verwenden, oder kann ich etwas direkt auf dem Client tun? – emmby

+0

Siehe meine Eingabe .............. –

+1

Bestätigt, dass es sich um einen Android-Fehler handelt, und wir finden ihn hier: http://code.google.com/p/android/issues/ Detail? id = 7786 –

0

Können Sie überprüfen, dass die Verbindung nicht geschlossen wird, bevor Sie die Antwort gelesen haben? Vielleicht parst HttpClient den Antwortcode sofort und speichert ihn für zukünftige Abfragen, aber HttpURLConnection könnte -1 zurückgeben, sobald die Verbindung geschlossen wird?

10

ich das gleiche Problem gestoßen bin, wenn ich nicht in allen Daten aus dem Inputstream gelesen hat, bevor er und das Öffnen einer zweiten Verbindung zu schließen. Es wurde auch entweder mit System.setProperty("http.keepAlive", "false"); oder einfach nur looping behoben, bis ich den Rest des InputStream gelesen habe.

Nicht vollständig mit Ihrem Problem verbunden, aber hoffe, dies hilft jedem anderen mit einem ähnlichen Problem.

5

Google bot eine elegante Abhilfe, da sie nur vor dem Froyo passiert:

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

Cf. http://android-developers.blogspot.ca/2011/09/androids-http-clients.html

+0

Perfekt arbeiten. Für mich geschah dies in api 4.1.1 während der Verwendung von Stripe. –

2

Oder Sie können HTTP-Header in der Verbindung (HttpURLConnection) gesetzt:

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