使用 Transfer-Encoding: chunked 改造客户端和响应
Retrofit client and response with Transfer-Encoding: chunked
我正在开发一个 Android 示例应用程序,它从 http://www.omdbapi.com/ 获取电影列表。
REST 服务是:
http://www.omdbapi.com/?s=star&apikey=d497e644
我正在使用 Retrofit 编写客户端。
public interface OmdbApi {
@Streaming
@GET("./")
@Headers({"Cache-control: no-cache"})
Call<Search> search(@Query("s") String search, @Query("apikey") String apiKey);
@Streaming
@GET("./")
@Headers({"Cache-control: no-cache"})
Call<FilmDetail> getFilm(@Query("i") String uid, @Query("apikey") String apiKey);
}
完整的源代码可用here。
当我 运行 应用程序时,我得到以下响应(取自 logcat):
OK http://www.omdbapi.com/?s=star&apikey=d497e644 (108ms)
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Cache-Control: public, max-age=86400
Expires: Sat, 26 May 2018 14:28:18 GMT
Last-Modified: Fri, 25 May 2018 05:39:04 GMT
Vary: *, Accept-Encoding
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Access-Control-Allow-Origin: *
CF-Cache-Status: HIT
Server: cloudflare
CF-RAY: 4208b00c817b3db9-MXP
Connection: Keep-Alive
并出现以下错误:
java.net.ProtocolException: unexpected end of stream
at okhttp3.internal.http1.Http1Codec$ChunkedSource.read(Http1Codec.java:455)
at okio.RealBufferedSource.read(RealBufferedSource.java:47)
okio.RealBufferedSource.exhausted(RealBufferedSource.java:57)
okio.InflaterSource.refill(InflaterSource.java:102)
okio.InflaterSource.read(InflaterSource.java:62)
okio.GzipSource.read(GzipSource.java:80)
okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:237)
okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200)
at okhttp3.RealCall.execute(RealCall.java:77)
at retrofit2.OkHttpCall.execute(OkHttpCall.java:180)
retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall.execute(ExecutorCallAdapterFactory.java:91)
com.abubusoft.filmfinder.service.repository.FilmRepository.lambda$findFilm[=13=]$FilmRepository(FilmRepository.java:18)
com.abubusoft.filmfinder.service.repository.FilmRepository$$Lambda[=13=].run(Unknown Source:20)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
经过一番调查,我发现问题是响应有Transfer-Encoding: chunked
。我该如何解决这个问题?
谢谢。
经过进一步调查:
- 我删除了
@Streaming
注释。它们没有用。
- 我所做的测试是在防火墙后面的 PC 上的模拟器上进行的。
OkHttp
多年前遇到过一些问题,但现在分块传输已完全管理。
- 在同一台机器上,在浏览器中调用相同的 URL 不会出现任何问题
我终于在另一台机器上尝试了 JUnit 测试和 Android 模拟器,我没有遇到任何问题。
最后,我确定代码可以正常工作,我用来开发应用程序的环境也有一些传输编码分块的问题。
完整的源代码可在此处获得:
我必须找出问题所在,我现在确定不是 Retrofit 或我的客户端定义或 OkHttp。
希望我的经验可以帮助到其他开发者。
拜耶兹
我正在开发一个 Android 示例应用程序,它从 http://www.omdbapi.com/ 获取电影列表。
REST 服务是:
http://www.omdbapi.com/?s=star&apikey=d497e644
我正在使用 Retrofit 编写客户端。
public interface OmdbApi {
@Streaming
@GET("./")
@Headers({"Cache-control: no-cache"})
Call<Search> search(@Query("s") String search, @Query("apikey") String apiKey);
@Streaming
@GET("./")
@Headers({"Cache-control: no-cache"})
Call<FilmDetail> getFilm(@Query("i") String uid, @Query("apikey") String apiKey);
}
完整的源代码可用here。
当我 运行 应用程序时,我得到以下响应(取自 logcat):
OK http://www.omdbapi.com/?s=star&apikey=d497e644 (108ms)
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Cache-Control: public, max-age=86400
Expires: Sat, 26 May 2018 14:28:18 GMT
Last-Modified: Fri, 25 May 2018 05:39:04 GMT
Vary: *, Accept-Encoding
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Access-Control-Allow-Origin: *
CF-Cache-Status: HIT
Server: cloudflare
CF-RAY: 4208b00c817b3db9-MXP
Connection: Keep-Alive
并出现以下错误:
java.net.ProtocolException: unexpected end of stream
at okhttp3.internal.http1.Http1Codec$ChunkedSource.read(Http1Codec.java:455)
at okio.RealBufferedSource.read(RealBufferedSource.java:47)
okio.RealBufferedSource.exhausted(RealBufferedSource.java:57)
okio.InflaterSource.refill(InflaterSource.java:102)
okio.InflaterSource.read(InflaterSource.java:62)
okio.GzipSource.read(GzipSource.java:80)
okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:237)
okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200)
at okhttp3.RealCall.execute(RealCall.java:77)
at retrofit2.OkHttpCall.execute(OkHttpCall.java:180)
retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall.execute(ExecutorCallAdapterFactory.java:91)
com.abubusoft.filmfinder.service.repository.FilmRepository.lambda$findFilm[=13=]$FilmRepository(FilmRepository.java:18)
com.abubusoft.filmfinder.service.repository.FilmRepository$$Lambda[=13=].run(Unknown Source:20)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
经过一番调查,我发现问题是响应有Transfer-Encoding: chunked
。我该如何解决这个问题?
谢谢。
经过进一步调查:
- 我删除了
@Streaming
注释。它们没有用。 - 我所做的测试是在防火墙后面的 PC 上的模拟器上进行的。
OkHttp
多年前遇到过一些问题,但现在分块传输已完全管理。- 在同一台机器上,在浏览器中调用相同的 URL 不会出现任何问题
我终于在另一台机器上尝试了 JUnit 测试和 Android 模拟器,我没有遇到任何问题。
最后,我确定代码可以正常工作,我用来开发应用程序的环境也有一些传输编码分块的问题。
完整的源代码可在此处获得:
我必须找出问题所在,我现在确定不是 Retrofit 或我的客户端定义或 OkHttp。
希望我的经验可以帮助到其他开发者。
拜耶兹