HttpURLConnection.getResponseCode () devuelve -1 en segunda invocación

Parece que me encuentro con un problema peculiar en Android 1.5 cuando una biblioteca que estoy usando (signpost 1.1-SNAPSHOT), hace dos conexiones consecutivas a un servidor remoto. La segunda conexión siempre falla con un HttpURLConnection.getResponseCode() de -1

He aquí un testcase que expone el 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); } } 

Básicamente, si firmo la solicitud y después consume toda la secuencia de entrada, la siguiente solicitud fallará con un resultado de -1. El fallo no parece ocurrir si acabo de leer un carácter del flujo de entrada.

Tenga en cuenta que esto no sucede para cualquier url – sólo urls específicos como el de arriba.

Además, si cambio a usar HttpClient en lugar de HttpURLConnection, todo funciona bien:

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

He encontrado referencias a lo que parece ser un problema similar en otros lugares, pero hasta ahora no hay soluciones. Si son verdaderamente el mismo problema, entonces el problema probablemente no está con la señal puesto que las otras referencias no hacen ninguna referencia a él.

¿Algunas ideas?

Intente establecer esta propiedad para ver si ayuda,

 http.keepAlive=false 

Vi problemas similares cuando la respuesta del servidor no es entendida por UrlConnection y cliente / servidor se descompone.

Si esto soluciona su problema, tiene que obtener una traza HTTP para ver exactamente lo que es especial acerca de la respuesta.

EDIT: Este cambio confirma mi sospecha. No soluciona tu problema. Sólo esconde el síntoma.

Si la respuesta de la primera solicitud es 200, necesitamos un rastro. Normalmente uso Ethereal / Wireshark para obtener el rastreo TCP.

Si su primera respuesta no es 200, veo un problema en su código. Con OAuth, la respuesta de error (401) en realidad devuelve datos, que incluye ProblemAdvice, Signature Base String etc para ayudarle a depurar. Necesita leer todo desde la secuencia de errores. De lo contrario, va a confundir la siguiente conexión y esa es la causa de -1. El ejemplo siguiente le muestra cómo manejar errores correctamente,

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

He encontrado el mismo problema cuando no leí en todos los datos del InputStream antes de cerrarlo y de abrir una segunda conexión. También se corrigió con System.setProperty("http.keepAlive", "false"); O simplemente simplemente hacer bucle hasta que he leído el resto de la InputStream.

No está completamente relacionado con tu problema, pero espero que esto ayude a alguien con un problema similar.

Google proporcionó una solución elegante ya que sólo está ocurriendo antes de 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

O bien, puede establecer un encabezado HTTP en la conexión (HttpUrlConnection):

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

¿Puede verificar que la conexión no se está cerrando antes de terminar de leer la respuesta? Tal vez HttpClient analiza el código de respuesta de inmediato, y lo guarda para consultas futuras, sin embargo HttpURLConnection podría estar regresando -1 una vez que la conexión se cierra?

  • Com.google.android.gms.auth.GoogleAuthException: Desconocido
  • Implementar OAuth2 con las credenciales de contraseña de propietario de recurso en Android
  • ¿Cómo uso OAuth 2.0 para enviar Gmail desde Indy?
  • OAuth + Twitter en Android: falla de devolución de llamada
  • Android Twitter no puede recuperar accestoken
  • ¿Existe ya una biblioteca OAuth2 para Java / Android?
  • Pestaña Chrome personalizada OAuth intercept redirect_uri
  • ¿Cómo / dónde almacenar el token de actualización en Android?
  • Inicia sesión de Google en la aplicación de Android para consumir Cloud Endpoints backend
  • Uso de los detalles de autenticación de Dropbox guardados en Android
  • ¿Por qué el flujo oauth2 nativo de Google requiere secreto de cliente?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.