java android oauth httpurlconnection signpost

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



android oauth (5)

¿Puedes verificar que la conexión no se cierra antes de terminar de leer la respuesta? Quizás HttpClient analice el código de respuesta de inmediato y lo guarde para futuras consultas, sin embargo, HttpURLConnection podría devolver -1 una vez que se cierre la conexión.

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

Aquí hay un caso de prueba 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 luego consumo toda la secuencia de entrada, la próxima solicitud fallará con un código de resultado de -1. La falla no parece ocurrir si solo leo un carácter de la secuencia de entrada.

Tenga en cuenta que esto no ocurre con ninguna URL, solo URL específicas como la anterior.

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 references a lo que parece ser un problema similar en otros lugares, pero hasta ahora no hay soluciones. Si realmente son el mismo problema, entonces el problema probablemente no sea con el poste indicador, ya que las otras referencias no hacen referencia a él.

¿Algunas ideas?


Google proporcionó una solución elegante ya que solo está sucediendo 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


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

No está completamente relacionado con su problema, pero espero que esto ayude a cualquier otra persona con un problema similar.


Intenta establecer esta propiedad para ver si ayuda,

http.keepAlive=false

Vi problemas similares cuando UrlConnection no entiende la respuesta del servidor y el cliente / servidor no se sincroniza.

Si esto resuelve su problema, debe obtener una traza HTTP para ver exactamente qué tiene de especial la respuesta.

EDITAR: Este cambio solo confirma mi sospecha. No resuelve tu problema. Simplemente oculta el síntoma.

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

Si su primera respuesta no es 200, veo un problema en su código. Con OAuth, la respuesta de error (401) realmente devuelve datos, que incluyen ProblemAdvice, Signature Base String, etc. para ayudarlo a depurar. Necesita leer todo de la corriente de error. De lo contrario, confundirá la próxima conexión y esa es la causa de -1. El siguiente ejemplo muestra cómo manejar los 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; } } }


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

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