Question

Il semble que je rencontre un problème particulier sur Android 1.5 lorsqu'une bibliothèque que j'utilise (panneau 1.1-SNAPSHOT) établit deux connexions consécutives sur un serveur distant. La deuxième connexion échoue toujours avec un HttpURLConnection.getResponseCode () de -1

Voici un cas de test qui expose le problème:

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

En gros, si je signe la demande puis que je consomme l’ensemble du flux d’entrée, la demande suivante échouera avec un code de résultat de -1. L'échec ne semble pas se produire si je ne lis qu'un seul caractère du flux d'entrée.

Notez que cela ne se produit pas pour les URL, mais uniquement pour des URL spécifiques telles que celle ci-dessus.

En outre, si je passe à l’utilisation de HttpClient à la place de HttpURLConnection, tout fonctionne correctement:

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

J'ai trouvé des références à ce qui semble être un problème similaire ailleurs, mais jusqu'à présent pas de solutions. S'il s'agit vraiment du même problème, le problème ne vient probablement pas de celui de poteau indicateur, car les autres références ne le mentionnent pas.

Des idées?

Était-ce utile?

La solution

Essayez de définir cette propriété pour voir si cela peut vous aider,

http.keepAlive=false

J'ai rencontré des problèmes similaires lorsque UrlConnection ne comprend pas la réponse du serveur et que le client / serveur n'est plus synchronisé.

Si cela résout votre problème, vous devez obtenir une trace HTTP pour savoir exactement ce qui est spécial dans la réponse.

EDIT: Ce changement ne fait que confirmer mes soupçons. Cela ne résout pas votre problème. Il cache juste le symptôme.

Si la réponse à la première demande est 200, nous avons besoin d'une trace. J'utilise normalement Ethereal / Wireshark pour obtenir la trace TCP.

Si votre première réponse n’est pas 200, je vois un problème dans votre code. Avec OAuth, la réponse d'erreur (401) renvoie en fait des données, qui comprennent ProblemAdvice, Signature Base String, etc. pour vous aider à déboguer. Vous devez tout lire depuis le flux d'erreur. Sinon, la prochaine connexion sera confuse et c'est la cause de -1. L'exemple suivant montre comment gérer correctement les erreurs,

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

Autres conseils

J'ai rencontré le même problème lorsque je ne lisais pas toutes les données du InputStream avant de le fermer et d'ouvrir une deuxième connexion. Il a également été corrigé avec System.setProperty ("http.keepAlive", "" false "); ou tout simplement en boucle jusqu'à ce que j'ai lu le reste du flux InputStream.

Pas complètement lié à votre problème, mais espérons que cela aidera tout le monde avec un problème similaire.

Google a fourni une solution de contournement élégante, car cela ne se produisait qu'avant 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

Vous pouvez également définir un en-tête HTTP dans la connexion (HttpUrlConnection):

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

Pouvez-vous vérifier que la connexion n'est pas fermée avant d'avoir fini de lire la réponse? Peut-être que HttpClient analyse immédiatement le code de réponse et l’enregistre pour les futures requêtes, mais HttpURLConnection pourrait renvoyer -1 une fois la connexion fermée?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top