Domanda

Mi sembra di riscontrare un problema particolare su Android 1.5 quando una libreria che sto utilizzando (cartello 1.1-SNAPSHOT), effettua due connessioni consecutive a un server remoto. La seconda connessione fallisce sempre con un HttpURLConnection.getResponseCode () di -1

Ecco una testcase che espone il problema:

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

Fondamentalmente, se firmo la richiesta e quindi utilizzo l'intero flusso di input, la richiesta successiva avrà esito negativo con un codice risultato di -1. L'errore non sembra accadere se leggo solo un carattere dal flusso di input.

Nota che ciò non accade per nessun url, ma solo per URL specifici come quello sopra.

Inoltre, se passo a utilizzare HttpClient invece di HttpURLConnection, tutto funziona perfettamente:

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

Ho trovato riferimenti a ciò che sembra essere un problema simile altrove, ma finora nessuna soluzione. Se sono davvero lo stesso problema, probabilmente il problema non è con il cartello poiché gli altri riferimenti non ne fanno riferimento.

Qualche idea?

È stato utile?

Soluzione

Prova a impostare questa proprietà per vedere se aiuta,

http.keepAlive=false

Ho riscontrato problemi simili quando UrlConnection non ha compreso la risposta del server e il client / server non è sincronizzato.

Se questo risolve il tuo problema, devi ottenere una traccia HTTP per vedere esattamente cosa c'è di speciale nella risposta.

EDIT: questa modifica conferma solo il mio sospetto. Non risolve il tuo problema. Nasconde solo il sintomo.

Se la risposta della prima richiesta è 200, abbiamo bisogno di una traccia. Normalmente uso Ethereal / Wireshark per ottenere la traccia TCP.

Se la tua prima risposta non è 200, vedo un problema nel tuo codice. Con OAuth, la risposta all'errore (401) in realtà restituisce dati, tra cui ProblemAdvice, Signature Base String ecc. Per aiutarti a eseguire il debug. Devi leggere tutto dal flusso di errori. Altrimenti, confonderà la prossima connessione e questa è la causa di -1. L'esempio seguente mostra come gestire correttamente gli errori,

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

Altri suggerimenti

Ho riscontrato lo stesso problema quando non ho letto tutti i dati da InputStream prima di chiuderlo e aprire una seconda connessione. È stato anche risolto con System.setProperty (" http.keepAlive " ;, " false "); o semplicemente semplicemente in loop fino a quando non ho letto il resto di InputStream.

Non completamente correlato al tuo problema, ma spero che questo aiuti chiunque altro con un problema simile.

Google ha fornito una soluzione alternativa dal momento che sta accadendo solo prima di 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");
    }
}

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

In alternativa, è possibile impostare l'intestazione HTTP nella connessione (HttpUrlConnection):

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

Puoi verificare che la connessione non si chiuda prima di aver finito di leggere la risposta? Forse HttpClient analizza immediatamente il codice di risposta e lo salva per query future, tuttavia HttpURLConnection potrebbe restituire -1 una volta chiusa la connessione?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top