android fields L'utilizzo del modello Spring Rest causa EOFException




spring rest ignore null fields (4)

Anche questo mi ha fatto correre Jelly Bean 4.2. Dopo la ricerca, sembra che stia accadendo a causa di una combinazione di Keep-Alive impostato e utilizzando il client HTTP J2SE standard, che credo sia HttpURLConnection.

Ci sono 2 soluzioni che posso confermare sono corrette.

1) Disattiva Keep-Alive.
Per me, la soluzione data nella risposta di Sebastian, System.setProperty ("http.keepAlive", "false"); non ha funzionato Dovevo usare

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

e invia quelle intestazioni in un HttpEntity nel RestTemplate.
Come accennato, questa soluzione potrebbe avere un impatto sulle prestazioni

2) Cambia il client HTTP.
In Spring per Android (testato su 1.0.1.RELEASE, ma potrebbe essere anche nelle versioni precedenti), il client HTTP predefinito per un'istanza RestTemplate è determinato dalla versione di Android sul dispositivo. L'API 9 o versione successiva utilizza HttpURLConnection, i vecchi utilizza HTTPClient. Per impostare esplicitamente il client su quello vecchio, utilizzare

restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());

Maggiori informazioni possono essere trovate qui: http://static.springsource.org/spring-android/docs/1.0.1.RELEASE/reference/htmlsingle/#d4e34
Non sono sicuro di quale impatto avrà sul rendimento, ma suppongo che sia più performante di un'app che non funziona.

Ad ogni modo, spero che aiuti qualcuno. Ho appena sprecato una settimana a caccia di oche selvatiche a caccia di questo.

Sto ricevendo java.io.EOFException quando uso il modello Spring REST su Android.

La causa dello stacktrace si legge così:

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

Un altro stacktrace simile:

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

Tutto questo accade su Android 4.1.2, installato sul mio tablet Xoom.

Il problema appare e scompare. Non è innescato da lunghe richieste neanche. La parte server è in esecuzione su una macchina all'interno della rete locale. Quando provo a eseguire le chiamate API tramite curl , funziona perfettamente.

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

Il modello di riposo è configurato in questo modo:

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 chiamata API in questione che si è arrestata qui è descritta nell'interfaccia basata su annotazioni Android:

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

Cose che ho provato:

  • Rimosso LoggingInterceptor
  • Chiamato tutte le chiamate API da CURL
  • Chiamata rimossa BufferingClientHttpRequestFactory - Aiutato un po 'ma l'errore si verifica ancora.
  • Testato su Android 2.3 - l'errore non può essere riprodotto

Ho letto vari post sui forum, l'eccezione EOF sembra apparire se gli URL non sono corretti, cosa che ho verificato in questo caso.

Inoltre, una volta verificata l'eccezione EOF, la chiamata non raggiunge nemmeno il lato server.

Dove sarebbe un buon punto per continuare la ricerca di una correzione? Si tratta di un inconveniente di Android 4.1?

Durante il debug di questo problema, ho trovato anche https://jira.springsource.org/browse/ANDROID-102 che mi ha impedito di vedere l'errore reale (EOF) prima.

Aggiornamento: trovato semplicemente http://code.google.com/p/google-http-java-client/issues/detail?id=116 - potrebbe essere correlato.

La correzione è anche delineata in https://codereview.appspot.com/6225045/ - quindi potrebbe essere stato unito per 4.1.


Recentemente ho affrontato questo problema e riuscirò a risolvere questo problema dopo aver impostato le intestazioni con il seguente codice:

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

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

restTemplate.postForObject......

http://code.google.com/p/google-http-java-client/issues/detail?id=116 contiene una soluzione alternativa nell'ultimo commento:

Questo è sicuramente collegato in qualche modo con le connessioni keepAlive.

Quando utilizzo: System.setProperty ("http.keepAlive", "false"); i problemi scompaiono.

Ma dalla mia comprensione le connessioni keep alive aumentano notevolmente le prestazioni, quindi è meglio non disabilitarle.

Im anche awere che mantenere in vita dovrebbe essere disabilitato per le vecchie versioni, ma il mio dispositivo è Jelly Bean.

Una volta applicato l'errore è scomparso.
Sembra che non sia interamente correlato a Spring, ma a un problema con JB.







android-annotations