restTemplate ResourceAccessException при перезагрузке сервера

Я использую restTemplate (из весеннего фреймворка Android) в своем приложении для Android, чтобы связаться с сервером отдыха с помощью post, я использую AsyncTask для отправки запроса и два класса Request и Response, которые POJO отправляют в форме Json.

public class RequestSender extends AsyncTask<Object, Void, Response> {
    private RestTemplate restTemplate = new RestTemplate();
    private static final String SERVER_REQUEST_PATH = "/path/to/rest/service";

    @Override
    protected Response doInBackground(Object... args) {
        String url = (String) args[0] + SERVER_REQUEST_PATH;
        Request requestArgs = (Request) args[1];
            Response response = null;

        restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
        try {
               response = restTemplate.postForObject(url, requestArgs, Response.class);
        } catch (RestClientException e) {
            e.printStackTrace();
            response = null;
        }
        return response;
    }
}

Как видите, код довольно прост и работает нормально в большинстве случаев, но не в определенной последовательности:

  1. Я делаю первый (или более) запрос к серверу;
  2. Я перезагружаю сервер без перезапуска приложения;
  3. Я делаю новый запрос к серверу;

Тогда первый запрос после перезагрузки сервера (шаг 3) не отправляется на сервер методом postForObject(...), а следующие. Этот первый запрос выдает мне ошибку вместо:

07-10 10:24:13.402: W/System.err(4827): org.springframework.web.client.ResourceAccessException: I/O error: null; nested exception is java.io.EOFException
    07-10 10:24:13.402: W/System.err(4827):     at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:491)
    07-10 10:24:13.402: W/System.err(4827):     at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:439)
    07-10 10:24:13.402: W/System.err(4827):     at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:317)
    07-10 10:24:13.402: W/System.err(4827):     at com.myapp.servercommunication.RequestSender.doInBackground(RequestSender.java:42)
    07-10 10:24:13.406: W/System.err(4827):     at com.myapp.servercommunication.RequestSender.doInBackground(RequestSender.java:1)
    07-10 10:24:13.406: W/System.err(4827):     at android.os.AsyncTask$2.call(AsyncTask.java:287)
    07-10 10:24:13.406: W/System.err(4827):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
    07-10 10:24:13.406: W/System.err(4827):     at java.util.concurrent.FutureTask.run(FutureTask.java:137)
    07-10 10:24:13.406: W/System.err(4827):     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
    07-10 10:24:13.406: W/System.err(4827):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
    07-10 10:24:13.406: W/System.err(4827):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
    07-10 10:24:13.406: W/System.err(4827):     at java.lang.Thread.run(Thread.java:856)
    07-10 10:24:13.409: W/System.err(4827): Caused by: java.io.EOFException
    07-10 10:24:13.413: W/System.err(4827):     at libcore.io.Streams.readAsciiLine(Streams.java:203)
    07-10 10:24:13.417: W/System.err(4827):     at libcore.net.http.HttpEngine.readResponseHeaders(HttpEngine.java:560)
    07-10 10:24:13.417: W/System.err(4827):     at libcore.net.http.HttpEngine.readResponse(HttpEngine.java:813)
    07-10 10:24:13.417: W/System.err(4827):     at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:274)
    07-10 10:24:13.417: W/System.err(4827):     at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:486)
    07-10 10:24:13.417: W/System.err(4827):     at org.springframework.http.client.SimpleClientHttpResponse.getRawStatusCode(SimpleClientHttpResponse.java:54)
    07-10 10:24:13.417: W/System.err(4827):     at org.springframework.http.client.SimpleClientHttpResponse.getStatusCode(SimpleClientHttpResponse.java:80)
    07-10 10:24:13.421: W/System.err(4827):     at org.springframework.web.client.DefaultResponseErrorHandler.hasError(DefaultResponseErrorHandler.java:46)
    07-10 10:24:13.421: W/System.err(4827):     at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:477)
    07-10 10:24:13.421: W/System.
    err(4827):  ... 11 more

Даже если сценарий использования не важен, мне интересно, почему эта ошибка выдается, есть ли проблема с моей реализацией, или это вполне нормальное поведение RestTemplate?

3 ответа

Решение

Нет сомнения java.io.EOFException появляется на стороне сервера. Если вы используете keep-alive на стороне сервера - отключите его следующим образом:

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

или это: System.setProperty("http.keepAlive", "false");

Другим решением является изменение http-клиента. В Spring для Android HTTP-клиент по умолчанию для RestTemplate определяется версией Android на устройстве. API 9 или новее использует HttpURLConnection, старше использует HTTPClient, Чтобы явно установить клиент на старый, используйте yourRestTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());

Пожалуйста, обратитесь сюда: http://static.springsource.org/spring-android/docs/1.0.1.RELEASE/reference/htmlsingle/

весна RestTemplate не является идеальным клиентом REST, и, к сожалению, в рабочем коде с ним много проблем.

Если вы используете новый Spring-Android v.2.0.0.M3 его необходимо включить Maven

        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient-android</artifactId>
            <version>4.3.5.1</version>
        </dependency>

или Gradle

dependencies {
    compile('org.apache.httpcomponents:httpclient-android:4.3.5.1')
}

Если Spring для Android обнаружит HttpClient 4.3, он автоматически настроит его в качестве ClientHttpRequestFactory по умолчанию

Недавно я столкнулся с той же проблемой при отправке запроса из шаблона REST. Мы много пытались добавить "http.keepAlive" в заголовки HTTP, но это работало несколько раз, а иногда не получалось. Наконец, мы смогли решить эту проблему после установки заголовков "Accept-Language" со следующим фрагментом кода:

HttpHeaders headers = new HttpHeaders();
headers.set("Accept-Language", "en-US,en;q=0.8");
Другие вопросы по тегам