android spring eof android-annotations

android - El uso de Spring Rest Template causa EOFException



android-annotations (4)

Este me mordió también, ejecutando Jelly Bean 4.2. Después de investigar, parece que está sucediendo debido a una combinación de Keep-Alive que se está configurando y utilizando el Cliente HTTP J2SE estándar, que creo que es HttpURLConnection.

Hay 2 soluciones que puedo confirmar son correctas.

1) Apaga Keep-Alive.
Para mí, la solución dada en la respuesta de Sebastian, System.setProperty ("http.keepAlive", "false"); no funcionó Tuve que usar

HttpHeaders headers = new HttpHeaders(); headers.set("Connection", "Close");

y envía esos encabezados en un HttpEntity en RestTemplate.
Como se mencionó, esta solución podría tener un impacto en el rendimiento

2) Cambiar el cliente HTTP.
En Spring para Android (probado en 1.0.1.RELEASE, pero también podría estar en versiones anteriores), el Cliente HTTP predeterminado para una instancia de RestTemplate está determinado por la versión de Android en el dispositivo. La API 9 o posterior usa HttpURLConnection, la anterior usa HTTPClient. Para establecer explícitamente el cliente al anterior, use

restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());

Puede encontrar más información aquí: http://static.springsource.org/spring-android/docs/1.0.1.RELEASE/reference/htmlsingle/#d4e34
No estoy seguro del impacto que esto tendrá en el rendimiento, pero creo que es más eficiente que una aplicación que no funciona.

De todos modos, espero que eso ayude a alguien. Solo perdí una semana de ganso, persiguiendo a este.

Estoy recibiendo java.io.EOFException cuando uso Spring REST template en Android.

La causa de stacktrace se lee así:

Caused by: java.io.EOFException at libcore.io.Streams.readAsciiLine(Streams.java:203) at libcore.net.http.HttpEngine.readResponseHeaders(HttpEngine.java:560) at libcore.net.http.HttpEngine.readResponse(HttpEngine.java:813) at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:274) at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:486) at org.springframework.http.client.SimpleClientHttpResponse.getRawStatusCode(SimpleClientHttpResponse.java:49) at org.springframework.http.client.SimpleClientHttpResponse.getStatusCode(SimpleClientHttpResponse.java:55) at org.springframework.http.client.BufferingClientHttpResponseWrapper.getStatusCode(BufferingClientHttpResponseWrapper.java:47) at com.company.util.LoggingClientHttpRequestInterceptor.intercept(LoggingClientHttpRequestInterceptor.java:33) at org.springframework.http.client.InterceptingClientHttpRequest$RequestExecution.execute(InterceptingClientHttpRequest.java:81) at com.company.api.interceptor.AuthTokenInterceptor.intercept(AuthTokenInterceptor.java:51) at org.springframework.http.client.InterceptingClientHttpRequest$RequestExecution.execute(InterceptingClientHttpRequest.java:81) at org.springframework.http.client.InterceptingClientHttpRequest.executeInternal(InterceptingClientHttpRequest.java:67) at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:46) at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:63) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:475) ... 14 more

Otro stacktrace similar:

org.springframework.web.client.ResourceAccessException: I/O error: null; nested exception is java.io.EOFException at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:490) at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:438) at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:414) at com.company.api.ApiClient_.logLoginAttempt(ApiClient_.java:299) at com.company.security.CompanyAuthenticationService$2.onCreateCall(CompanyAuthenticationService.java:206) at com.company.api.SafeApiCall.doInBackground(SafeApiCall.java:49) at com.company.api.SafeApiCall.doInBackground(SafeApiCall.java:22) at android.os.AsyncTask$2.call(AsyncTask.java:287) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) at java.util.concurrent.FutureTask.run(FutureTask.java:137) at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569) at java.lang.Thread.run(Thread.java:856) Caused by: java.io.EOFException at libcore.io.Streams.readAsciiLine(Streams.java:203) at libcore.net.http.HttpEngine.readResponseHeaders(HttpEngine.java:560) at libcore.net.http.HttpEngine.readResponse(HttpEngine.java:813) at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:274) at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:486) at org.springframework.http.client.SimpleClientHttpResponse.getRawStatusCode(SimpleClientHttpResponse.java:49) at org.springframework.http.client.SimpleClientHttpResponse.getStatusCode(SimpleClientHttpResponse.java:55) at org.springframework.http.client.BufferingClientHttpResponseWrapper.getStatusCode(BufferingClientHttpResponseWrapper.java:47) at org.springframework.web.client.DefaultResponseErrorHandler.hasError(DefaultResponseErrorHandler.java:46) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:476) ... 13 more

Todo esto sucede en Android 4.1.2, instalado en mi tableta Xoom.

El problema aparece y desaparece. No es desencadenado por solicitudes largas tampoco. La parte del servidor se ejecuta en una máquina dentro de la red local. Cuando trato de ejecutar API Calls a través de curl , funciona bien.

AuthTokenInterceptor :

@Override public ClientHttpResponse intercept(HttpRequest request, byte[] data, ClientHttpRequestExecution execution) throws IOException { HttpHeaders headers = request.getHeaders(); if (!StringUtils.isEmpty(mAuthToken)) { headers.add((mIsOAuth ? "Authorization" : "authToken"), (mIsOAuth ? "Bearer " : "") + mAuthToken); } return execution.execute(request, data); }

LoggingClientHttpRequestInterceptor :

/** {@inheritDoc} */ @Override public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException { Log.d(TAG, "To : " + httpRequest.getURI()); Log.d(TAG, "Method : " + httpRequest.getMethod().name()); Log.d(TAG, "Data : " + new String(bytes)); for (Object key : httpRequest.getHeaders().keySet()) { Log.d(TAG, "Header <" + key + ">: " + httpRequest.getHeaders().get(key)); } final ClientHttpResponse response = clientHttpRequestExecution.execute(httpRequest, bytes); if (response != null) { Log.d(TAG, "Response: " + response.getStatusCode()); if (response.getBody() != null) { Log.d(TAG, "Response: " + convertStreamToString(response.getBody())); } } else { Log.d(TAG, "Response: " + response); } return response; }

La plantilla de descanso se configura así:

final RestTemplate template = new RestTemplate(false); template.getMessageConverters().add(new MappingJacksonHttpMessageConverter()); template.setRequestFactory(new BufferingClientHttpRequestFactory(template.getRequestFactory())); ApiUtils.addAuthTokenHeaderToRestTemplate(template, mAuthToken, false); ApiUtils.addRequestLoggingToRestTemplate(template);

La llamada API en cuestión que se colgó aquí se describe en la interfaz basada en anotaciones de Android:

@Post("/user/memberships") @Accept(MediaType.APPLICATION_JSON) CompanyApiResponse saveGroupMembership(UserGroupMembership membership) throws RestClientException;

Cosas que he intentado:

  • Se eliminó el intérprete de registro
  • Llamadas a todas las llamadas API por CURL
  • Se eliminó la llamada BufferingClientHttpRequestFactory - Ayudó un poco, pero el error aún se produce.
  • Probado en Android 2.3 - el error no puede ser reproducido

He estado leyendo varias publicaciones de foros, la excepción de EOF parece aparecer si las URL son incorrectas, lo que comprobé dos veces en este caso.

También debe tenerse en cuenta que, una vez que se produce la Excepción de EOF, la llamada ni siquiera llega al lado del servidor.

¿Dónde sería un buen punto para continuar la búsqueda de una solución? ¿Es esto un inconveniente de Android 4.1?

Al depurar este problema, también encontré https://jira.springsource.org/browse/ANDROID-102 que me impidió ver el error real (EOF) anteriormente.

Actualización: Acabo de encontrar http://code.google.com/p/google-http-java-client/issues/detail?id=116 - podría estar relacionado.

La solución también se describe en https://codereview.appspot.com/6225045/ , por lo que podría haber sido fusionada para 4.1.


Recientemente me enfrenté a este problema y voy a poder resolver este problema después de configurar los encabezados con el siguiente fragmento de código:

headers.set("Accept-Language", "en-US,en;q=0.8");


http://code.google.com/p/google-http-java-client/issues/detail?id=116 contiene una solución en el último comentario:

Esto está defenetly conectado de alguna manera con las conexiones KeepAlive.

Cuando uso: System.setProperty ("http.keepAlive", "false"); los problemas desaparecen

Pero desde mi punto de vista, mantener las conexiones vivas aumentan en gran medida el rendimiento, por lo que es mejor no deshabilitarlas.

También dije que mantener vivo debe estar desactivado para las versiones antiguas, pero mi dispositivo es Jelly Bean.

Una vez aplicado, el error desapareció.
Parece que no está completamente relacionado con Spring, pero es un problema de JB.


RestTemplate restTemplate = new RestTemplate(); ((SimpleClientHttpRequestFactory)restTemplate.getRequestFactory()).setOutputStreaming(false); restTemplate.postForObject......