Retrofit 2.0.1 + okhttp 3.2.0: GET not working when connected to WiFi network (SocketTimeoutException)
See original GitHub issueI’ve found what appears to be a bug when performing a GET request to a private API. What is peculiar about this issue is the fact that even though it sometimes occurs when the Android device is connected to the mobile data network (around 10% of the time), on WiFi it just will never work, under any circumstance.
I’ve tested the same GET request using Postman, the private API’s swagger interface, and on iOS (AFNetworking), but when trying to get the Android app to perform the exact same request using Retrofit and okhttp, it fails to complete the request.
The response is JSON-formatted, and I’m using a GsonBuilder to deserialize it and turn it into a list of Java entity objects, as one would normally do. The response body is turned into a JsonReader through the GsonBuilder, which is then looped through using the hasNext() method, which in turn throws an IOException in the form of a SocketTimeoutException when waiting for the server to continue submitting data - this is done library-side. It looks like the serializer is able to serialize the first pack of data correctly, but the second one never arrives and that causes a peek() method to throw the exception.
I’m currently intercepting the request and response which show the following info (I’ve removed the address since it’s a private API I’m sending it to):
ApiManager: Sending request ********************* on null
ApiManager: Received response for ********************* Server: nginx/1.6.2 Vary: Accept, Cookie Cache-Control: max-age=600 Content-Type: application/json Date: Thu, 28 Apr 2016 20:36:37 GMT Expires: Thu, 28 Apr 2016 20:42:57 GMT Transfer-Encoding: chunked Connection: Keep-Alive Allow: GET, HEAD, OPTIONS X-Frame-Options: SAMEORIGIN Last-Modified: Thu, 28 Apr 2016 20:32:57 GMT OkHttp-Sent-Millis: 1461875797821 OkHttp-Received-Millis: 1461875798035
Here’s what I believe to be the relevant part of the code:
@GET(ApiConstants.ENDPOINT)
Call<List<Entity>> getEntityList();
...
public ApiManager( .... ) {
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(
new Interceptor() {
@Override
public okhttp3.Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();
request = request.newBuilder()
.addHeader(ApiConstants.AUTH_HEADER, ApiConstants.AUTH_VALUE)
.build();
okhttp3.Response response = chain.proceed(request);
return response;
}
})
.build();
Gson gson = new GsonBuilder()
.registerTypeAdapter(Entity.class, new EntityDeserializer())
.create();
mRetrofitClient = new Retrofit.Builder()
.baseUrl(ApiConstants.BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
mApiService = mRetrofitClient.create(ApiInterface.class);
......
mApiManager.getService().getEntityList().enqueue(new Callback<List<Entity>>() {
@Override
public void onResponse(Call<List<Entity>> call, Response<List<Entity>> response) {
//Success
}
@Override
public void onFailure(Call<List<Entity>> call, Throwable t) {
//Always falls here on WiFi, gets SocketTimeoutException.
}
});
Finally, here’s the exception:
> 04-28 14:50:50.432 3463-3463/com.package.dev W/System.err: java.net.SocketTimeoutException: timeout
> 04-28 14:50:50.435 3463-3463/com.package.dev W/System.err: at okio.Okio$3.newTimeoutException(Okio.java:212)
> 04-28 14:50:50.435 3463-3463/com.package.dev W/System.err: at okio.AsyncTimeout.exit(AsyncTimeout.java:288)
> 04-28 14:50:50.435 3463-3463/com.package.dev W/System.err: at okio.AsyncTimeout$2.read(AsyncTimeout.java:242)
> 04-28 14:50:50.435 3463-3463/com.package.dev W/System.err: at okio.RealBufferedSource.read(RealBufferedSource.java:45)
> 04-28 14:50:50.435 3463-3463/com.package.dev W/System.err: at okhttp3.internal.http.Http1xStream$ChunkedSource.read(Http1xStream.java:426)
> 04-28 14:50:50.435 3463-3463/com.package.dev W/System.err: at okio.RealBufferedSource.read(RealBufferedSource.java:45)
> 04-28 14:50:50.435 3463-3463/com.package.dev W/System.err: at okio.ForwardingSource.read(ForwardingSource.java:35)
> 04-28 14:50:50.435 3463-3463/com.package.dev W/System.err: at retrofit2.OkHttpCall$ExceptionCatchingRequestBody$1.read(OkHttpCall.java:279)
> 04-28 14:50:50.435 3463-3463/com.package.dev W/System.err: at okio.RealBufferedSource$1.read(RealBufferedSource.java:367)
> 04-28 14:50:50.435 3463-3463/com.package.dev W/System.err: at java.io.InputStreamReader.read(InputStreamReader.java:233)
> 04-28 14:50:50.435 3463-3463/com.package.dev W/System.err: at com.google.gson.stream.JsonReader.fillBuffer(JsonReader.java:1293)
> 04-28 14:50:50.435 3463-3463/com.package.dev W/System.err: at com.google.gson.stream.JsonReader.peekKeyword(JsonReader.java:626)
> 04-28 14:50:50.436 3463-3463/com.package.dev W/System.err: at com.google.gson.stream.JsonReader.doPeek(JsonReader.java:583)
> 04-28 14:50:50.436 3463-3463/com.package.dev W/System.err: at com.google.gson.stream.JsonReader.peek(JsonReader.java:429)
> 04-28 14:50:50.436 3463-3463/com.package.dev W/System.err: at com.google.gson.internal.bind.TypeAdapters$29.read(TypeAdapters.java:720)
> 04-28 14:50:50.436 3463-3463/com.package.dev W/System.err: at com.google.gson.internal.bind.TypeAdapters$29.read(TypeAdapters.java:743)
> 04-28 14:50:50.436 3463-3463/com.package.dev W/System.err: at com.google.gson.internal.bind.TypeAdapters$29.read(TypeAdapters.java:718)
> 04-28 14:50:50.436 3463-3463/com.package.dev W/System.err: at com.google.gson.internal.Streams.parse(Streams.java:48)
> 04-28 14:50:50.436 3463-3463/com.package.dev W/System.err: at com.google.gson.TreeTypeAdapter.read(TreeTypeAdapter.java:54)
> 04-28 14:50:50.436 3463-3463/com.package.dev W/System.err: at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40)
> 04-28 14:50:50.436 3463-3463/com.package.dev W/System.err: at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82)
> 04-28 14:50:50.436 3463-3463/com.package.dev W/System.err: at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61)
> 04-28 14:50:50.436 3463-3463/com.package.dev W/System.err: at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:116)
> 04-28 14:50:50.436 3463-3463/com.package.dev W/System.err: at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:216)
> 04-28 14:50:50.436 3463-3463/com.package.dev W/System.err: at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:37)
> 04-28 14:50:50.436 3463-3463/com.package.dev W/System.err: at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:25)
> 04-28 14:50:50.436 3463-3463/com.package.dev W/System.err: at retrofit2.ServiceMethod.toResponse(ServiceMethod.java:116)
> 04-28 14:50:50.436 3463-3463/com.package.dev W/System.err: at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:211)
> 04-28 14:50:50.436 3463-3463/com.package.dev W/System.err: at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:106)
> 04-28 14:50:50.436 3463-3463/com.package.dev W/System.err: at okhttp3.RealCall$AsyncCall.execute(RealCall.java:133)
> 04-28 14:50:50.436 3463-3463/com.package.dev W/System.err: at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
> 04-28 14:50:50.436 3463-3463/com.package.dev W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
> 04-28 14:50:50.436 3463-3463/com.package.dev W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
> 04-28 14:50:50.436 3463-3463/com.package.dev W/System.err: at java.lang.Thread.run(Thread.java:818)
> 04-28 14:50:50.436 3463-3463/com.package.dev W/System.err: Caused by: java.net.SocketTimeoutException
> 04-28 14:50:50.439 3463-3463/com.package.dev W/System.err: at java.net.PlainSocketImpl.read(PlainSocketImpl.java:484)
> 04-28 14:50:50.439 3463-3463/com.package.dev W/System.err: at java.net.PlainSocketImpl.-wrap0(PlainSocketImpl.java)
> 04-28 14:50:50.439 3463-3463/com.package.dev W/System.err: at java.net.PlainSocketImpl$PlainSocketInputStream.read(PlainSocketImpl.java:237)
> 04-28 14:50:50.439 3463-3463/com.package.dev W/System.err: at okio.Okio$2.read(Okio.java:140)
> 04-28 14:50:50.439 3463-3463/com.package.dev W/System.err: at okio.AsyncTimeout$2.read(AsyncTimeout.java:238)
> 04-28 14:50:50.439 3463-3463/com.package.dev W/System.err: ... 31 more
Best case scenario, I’ve done something obviously wrong and you guys will point me in the right direction. If not, I’d appreciate any workarounds or potential ways to debug this issue and eventually resolve it. I’ve been doing some reading, and it seems to me like this is not a necessarily new thing, but from what I can see similar reports belong to previous versions of the library, and proposed fixes seem arbitrary and not well substantiated.
One of these, for example, involved disabling the tcp_timestamp parameter in the sysctl file on the server. However, I have no access to the file or the server and I’m not going to approach them without an explanation on why that would solve the issue. I’m mentioning it here because hopefully someone will be knowledgeable enough to tell me if that’s a good solution/thing to try and why, so I can try that, but I’m crossing my fingers that won’t be necessary.
Thanks for the attention. I can happily provide any more info if needed.
Issue Analytics
- State:
- Created 7 years ago
- Comments:25 (5 by maintainers)
Top GitHub Comments
@Fireblend Hi, Even i facing the similar issue . One of the api’s doesn’t fetch me the result and throw socketTimeout exception. Could you solve the issue? Any help would be appriciated
Hi, Even i facing the same issue any help would be appriciated