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:
- ¿Cómo implementar correctamente el inicio de sesión linkedIn?
- Cómo revocar el permiso que mi aplicación recibe del usuario google gmail AccountManager.getAuthToken (
- Buscando un ejemplo de trabajo (proyecto completo) para OAuth 2.0 Acceso a gmail
- Autenticación con OAuth2 para una aplicación * y * un sitio web
- Java.lang.NoClassDefFoundError: oauth.signpost.commonshttp.CommonsHttpOAuthConsumer android
// 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?
- Cifrar datos en SharedPreferences
- ¿Cuáles son los riesgos de exponer la clave no tan secreta? ¿Hay alguna solución?
- ¿Cómo mantener seguro el secreto del consumidor de OAuth y cómo reaccionar cuando está comprometido?
- El esquema personalizado no parece iniciarse en la intención de la aplicación
- ¿Cómo verificar correctamente la integridad de un token de Google?
- Problema con OAuth, Twitter y Android: falla en la comunicación http con el servidor
- Cómo configurar el encabezado de autorización (OAuth token) en una solicitud Android OKHTTPClient
- Algunas preguntas sobre OAuth y Android
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?
- ¿Qué es authorizedEntity? No se puede encontrar gcm_defaultSenderId en la propia aplicación.
- Android Studio Gradle problema de actualización a la versión 0.5.0 – Gradle de la migración de 0,8 a 0,9 – También Android Studio actualización a 0,8.1