OkHttpClient 有时会得到不完整的 json 响应
OkHttpClient sometimes getting incomplete json response
我一直面临这个不完整的 json 错误,无法找到问题所在。 API 响应在 POSTMAN 中工作正常。但是这个问题发生在我的 android 模拟器中,而且它只是随机发生的。这个项目是用 kotlin dagger-hilt retrofit2 okhttp3 gson 构建的。
成功响应
I/okhttp.OkHttpClient: <-- 200 OK http://10.0.2.2:8000/api/v1/user/friend/mutual?name=as (217ms)
I/okhttp.OkHttpClient: Host: 10.0.2.2:8000
I/okhttp.OkHttpClient: Date: Thu, 03 Mar 2022 06:38:59 GMT
I/okhttp.OkHttpClient: Connection: close
I/okhttp.OkHttpClient: X-Powered-By: PHP/7.4.13
I/okhttp.OkHttpClient: Cache-Control: no-cache, private
I/okhttp.OkHttpClient: Date: Thu, 03 Mar 2022 06:38:59 GMT
I/okhttp.OkHttpClient: Content-Type: application/json
I/okhttp.OkHttpClient: X-RateLimit-Limit: 60
I/okhttp.OkHttpClient: X-RateLimit-Remaining: 52
I/okhttp.OkHttpClient: Access-Control-Allow-Origin: *
I/okhttp.OkHttpClient: {"friends":[{"user_id":16,"name":"Grant Erdman","username":"lilla.kulas","email":"claudie04@example.org","image":"https:\/\/via.placeholder.com\/640x480.png\/00dd44?text=dolor","relationship":"friend"}],"requests":[]}
I/okhttp.OkHttpClient: <-- END HTTP (217-byte body)
不完整Json 缺少响应“}”
I/okhttp.OkHttpClient: <-- 200 OK http://10.0.2.2:8000/api/v1/user/friend/mutual?name=as (198ms)
I/okhttp.OkHttpClient: Host: 10.0.2.2:8000
I/okhttp.OkHttpClient: Date: Thu, 03 Mar 2022 06:39:00 GMT
I/okhttp.OkHttpClient: Connection: close
I/okhttp.OkHttpClient: X-Powered-By: PHP/7.4.13
I/okhttp.OkHttpClient: Cache-Control: no-cache, private
I/okhttp.OkHttpClient: Date: Thu, 03 Mar 2022 06:39:00 GMT
I/okhttp.OkHttpClient: Content-Type: application/json
I/okhttp.OkHttpClient: X-RateLimit-Limit: 60
I/okhttp.OkHttpClient: X-RateLimit-Remaining: 51
I/okhttp.OkHttpClient: Access-Control-Allow-Origin: *
I/okhttp.OkHttpClient: {"friends":[{"user_id":16,"name":"Grant Erdman","username":"lilla.kulas","email":"claudie04@example.org","image":"https:\/\/via.placeholder.com\/640x480.png\/00dd44?text=dolor","relationship":"friend"}],"requests":[]
I/okhttp.OkHttpClient: <-- END HTTP (216-byte body)
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.findplan, PID: 4695
java.io.EOFException: End of input at line 1 column 217 path $.requests
at com.google.gson.stream.JsonReader.nextNonWhitespace(JsonReader.java:1395)
at com.google.gson.stream.JsonReader.doPeek(JsonReader.java:481)
at com.google.gson.stream.JsonReader.hasNext(JsonReader.java:413)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:216)
at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:40)
at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:27)
at com.example.findplan.utils.NullOnEmptyConverterFactory.convert(NullOnEmptyConverterFactory.java:20)
at com.example.findplan.utils.NullOnEmptyConverterFactory.convert(NullOnEmptyConverterFactory.java:16)
at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:243)
at retrofit2.OkHttpCall.onResponse(OkHttpCall.java:153)
at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
I/Process: Sending signal. PID: 4695 SIG: 9
我的网络模块
@Singleton
@Provides
fun provideOkHttpClient(mySharedPreferences: MySharedPreferences): OkHttpClient {
val builder = OkHttpClient
.Builder()
.connectTimeout(1, TimeUnit.MINUTES)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
val authenticationInterceptor = AuthenticationInterceptor(mySharedPreferences)
builder.addInterceptor(authenticationInterceptor)
val interceptor = HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY);
builder.addNetworkInterceptor(interceptor)
return builder.build()
}
@Singleton
@Provides
fun provideGson(): Gson {
return GsonBuilder()
.setLenient()
.create()
}
@Singleton
@Provides
fun provideRetrofit(gson: Gson, okHttpClient: OkHttpClient): Retrofit {
return Retrofit.Builder()
.baseUrl(BuildConfig.BASE_URL)
.client(okHttpClient)
.addConverterFactory(NullOnEmptyConverterFactory())
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
}
NullOnEmptyConverterFactory
public class NullOnEmptyConverterFactory extends Converter.Factory {
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
final Converter<ResponseBody, ?> delegate = retrofit.nextResponseBodyConverter(this, type, annotations);
return new Converter<ResponseBody, Object>() {
@Override
public Object convert(ResponseBody body) throws IOException {
if (body.contentLength() == 0) return null;
return delegate.convert(body);
}
};
}
}
我怀疑 Android 模拟器可能会在这里干扰您。我已经看到它行为不端的问题,尤其是在 Windows.
上
https://issuetracker.google.com/issues/119027639
如果您想解决此问题,请考虑将您的服务器更改为使用 Connection: close
以外的其他内容来终止您的响应 body。也许分块编码或 content-length header.
我一直面临这个不完整的 json 错误,无法找到问题所在。 API 响应在 POSTMAN 中工作正常。但是这个问题发生在我的 android 模拟器中,而且它只是随机发生的。这个项目是用 kotlin dagger-hilt retrofit2 okhttp3 gson 构建的。
成功响应
I/okhttp.OkHttpClient: <-- 200 OK http://10.0.2.2:8000/api/v1/user/friend/mutual?name=as (217ms)
I/okhttp.OkHttpClient: Host: 10.0.2.2:8000
I/okhttp.OkHttpClient: Date: Thu, 03 Mar 2022 06:38:59 GMT
I/okhttp.OkHttpClient: Connection: close
I/okhttp.OkHttpClient: X-Powered-By: PHP/7.4.13
I/okhttp.OkHttpClient: Cache-Control: no-cache, private
I/okhttp.OkHttpClient: Date: Thu, 03 Mar 2022 06:38:59 GMT
I/okhttp.OkHttpClient: Content-Type: application/json
I/okhttp.OkHttpClient: X-RateLimit-Limit: 60
I/okhttp.OkHttpClient: X-RateLimit-Remaining: 52
I/okhttp.OkHttpClient: Access-Control-Allow-Origin: *
I/okhttp.OkHttpClient: {"friends":[{"user_id":16,"name":"Grant Erdman","username":"lilla.kulas","email":"claudie04@example.org","image":"https:\/\/via.placeholder.com\/640x480.png\/00dd44?text=dolor","relationship":"friend"}],"requests":[]}
I/okhttp.OkHttpClient: <-- END HTTP (217-byte body)
不完整Json 缺少响应“}”
I/okhttp.OkHttpClient: <-- 200 OK http://10.0.2.2:8000/api/v1/user/friend/mutual?name=as (198ms)
I/okhttp.OkHttpClient: Host: 10.0.2.2:8000
I/okhttp.OkHttpClient: Date: Thu, 03 Mar 2022 06:39:00 GMT
I/okhttp.OkHttpClient: Connection: close
I/okhttp.OkHttpClient: X-Powered-By: PHP/7.4.13
I/okhttp.OkHttpClient: Cache-Control: no-cache, private
I/okhttp.OkHttpClient: Date: Thu, 03 Mar 2022 06:39:00 GMT
I/okhttp.OkHttpClient: Content-Type: application/json
I/okhttp.OkHttpClient: X-RateLimit-Limit: 60
I/okhttp.OkHttpClient: X-RateLimit-Remaining: 51
I/okhttp.OkHttpClient: Access-Control-Allow-Origin: *
I/okhttp.OkHttpClient: {"friends":[{"user_id":16,"name":"Grant Erdman","username":"lilla.kulas","email":"claudie04@example.org","image":"https:\/\/via.placeholder.com\/640x480.png\/00dd44?text=dolor","relationship":"friend"}],"requests":[]
I/okhttp.OkHttpClient: <-- END HTTP (216-byte body)
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.findplan, PID: 4695
java.io.EOFException: End of input at line 1 column 217 path $.requests
at com.google.gson.stream.JsonReader.nextNonWhitespace(JsonReader.java:1395)
at com.google.gson.stream.JsonReader.doPeek(JsonReader.java:481)
at com.google.gson.stream.JsonReader.hasNext(JsonReader.java:413)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:216)
at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:40)
at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:27)
at com.example.findplan.utils.NullOnEmptyConverterFactory.convert(NullOnEmptyConverterFactory.java:20)
at com.example.findplan.utils.NullOnEmptyConverterFactory.convert(NullOnEmptyConverterFactory.java:16)
at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:243)
at retrofit2.OkHttpCall.onResponse(OkHttpCall.java:153)
at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
I/Process: Sending signal. PID: 4695 SIG: 9
我的网络模块
@Singleton
@Provides
fun provideOkHttpClient(mySharedPreferences: MySharedPreferences): OkHttpClient {
val builder = OkHttpClient
.Builder()
.connectTimeout(1, TimeUnit.MINUTES)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
val authenticationInterceptor = AuthenticationInterceptor(mySharedPreferences)
builder.addInterceptor(authenticationInterceptor)
val interceptor = HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY);
builder.addNetworkInterceptor(interceptor)
return builder.build()
}
@Singleton
@Provides
fun provideGson(): Gson {
return GsonBuilder()
.setLenient()
.create()
}
@Singleton
@Provides
fun provideRetrofit(gson: Gson, okHttpClient: OkHttpClient): Retrofit {
return Retrofit.Builder()
.baseUrl(BuildConfig.BASE_URL)
.client(okHttpClient)
.addConverterFactory(NullOnEmptyConverterFactory())
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
}
NullOnEmptyConverterFactory
public class NullOnEmptyConverterFactory extends Converter.Factory {
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
final Converter<ResponseBody, ?> delegate = retrofit.nextResponseBodyConverter(this, type, annotations);
return new Converter<ResponseBody, Object>() {
@Override
public Object convert(ResponseBody body) throws IOException {
if (body.contentLength() == 0) return null;
return delegate.convert(body);
}
};
}
}
我怀疑 Android 模拟器可能会在这里干扰您。我已经看到它行为不端的问题,尤其是在 Windows.
上https://issuetracker.google.com/issues/119027639
如果您想解决此问题,请考虑将您的服务器更改为使用 Connection: close
以外的其他内容来终止您的响应 body。也许分块编码或 content-length header.