Java.io.EOFException
は、AndroidでSpring RESTテンプレートを使用している場合です。
スタックトレースの原因は次のとおりです。
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
別の同様のスタックトレース:
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
これはすべて、Android 4.1.2、私のXoomタブレットにインストールされている)で発生しています。
問題が発生して消えます。長いリクエストによってもトリガーされません。サーバー部分はローカルネットワーク内のマシンで実行されています。 curl
を介してAPI呼び出しを実行しようとすると、うまく機能します。
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;
}
Restテンプレートは次のように構成されています。
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);
ここでクラッシュした問題のAPI呼び出しは、Androidアノテーションベースのインターフェースで説明されています:
@Post("/user/memberships")
@Accept(MediaType.APPLICATION_JSON)
CompanyApiResponse saveGroupMembership(UserGroupMembership membership) throws RestClientException;
私が試したこと:
私はさまざまなフォーラムの投稿を読んでいますが、URLが正しくない場合、EOF例外が表示されているようです。この場合、これを再確認しました。
また、EOF例外が発生すると、呼び出しはサーバー側にも到達しません。
修正の検索を続けるにはどこが良いでしょうか?これはAndroid 4.1不便ですか?
この問題のデバッグ中に、 https://jira.springsource.org/browse/Android-102 も見つかりました。これにより、以前に実際のエラー(EOF)が表示されませんでした。
更新:見つかりました http://code.google.com/p/google-http-Java-client/issues/detail? id = 116 -関連している可能性があります。
この修正の概要は https://codereview.appspot.com/6225045/ にも記載されているため、4.1にマージされている可能性があります。
これも私と同じように、Jelly Bean 4.2を実行しています。調査したところ、キープアライブが設定されているとの組み合わせが標準のJ2SE HTTPクライアントを使用しているために発生しているようです。
私が確認できる2つの解決策があります。
1)キープアライブをオフにします。
私にとって、セバスチャンの回答で与えられた解決策、System.setProperty( "http.keepAlive"、 "false");はしませんでしたt動作します。私は使用しなければなりませんでした
HttpHeaders headers = new HttpHeaders();
headers.set("Connection", "Close");
これらのヘッダーをRestTemplateのHttpEntityで送信します。
前述のように、このソリューションはパフォーマンスに影響を与える可能性があります
2)HTTPクライアントを変更します。
SpringでAndroid(1.0.1.RELEASEでテスト済みですが、以前のリリースでも可能))RestTemplateインスタンスのデフォルトのHTTPクライアントは、=のバージョンによって決定されますAndroid。API 9以降はHttpURLConnectionを使用し、古いものはHTTPClientを使用します。クライアントを明示的に古いものに設定するには、
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
詳細については、こちらをご覧ください: http://static.springsource.org/spring-Android/docs/1.0.1.RELEASE/reference/htmlsingle/#d4e34
これがパフォーマンスにどのような影響を与えるかはわかりませんが、機能しないアプリよりもパフォーマンスが高いと思います。
とにかく、それが誰かを助けることを願っています。私はこれを一週間野生のガチョウを追いかけて無駄にしました。
http://code.google.com/p/google-http-Java-client/issues/detail?id=116 には、最新のコメントに回避策が含まれています。
これは間違いなくなんとかしてkeepAlive接続と接続されています。
私が使用する場合:System.setProperty( "http.keepAlive"、 "false");問題が消えます。
しかし、私の理解では、キープアライブ接続はパフォーマンスを大幅に向上させるので、それらを無効にしない方が良いでしょう。
古いバージョンではキープアライブを無効にする必要があることにも気付いていましたが、私のデバイスはジェリービーンです。
適用するとエラーは消えました。
Springに完全に関連しているのではなく、JBの問題のようです。
最近この問題に直面し、次のコードでヘッダーを設定した後、この問題を解決できるようになります。
headers.set("Accept-Language", "en-US,en;q=0.8");