Retrofit和OkHttp gzip解码

35

我希望调用的REST服务的响应是经过gzip压缩的JSON格式。它提供了Content-Encoding: gzip,但我的OkHttp无法将其解码为可读文本,因此JSON转换器会抛出异常。

---> HTTP GET https://rapla.dhbw-karlsruhe.de/rapla/events?resources=%5B%27rc85dbd6-7d98-4eb7-a7f6-b867213c73d8%27%5D&start=2015-09-01&end=2015-12-31
Accept-Encoding: gzip, deflate
Accept: application/json
Authorization: *not posted*
Content-Type: application/json;charset=utf-8
---> END HTTP (no body)
<--- HTTP 200 https://rapla.dhbw-karlsruhe.de/rapla/events?resources=%5B%27rc85dbd6-7d98-4eb7-a7f6-b867213c73d8%27%5D&start=2015-09-01&end=2015-12-31 (13ms)
Date: Tue, 24 Nov 2015 09:09:10 GMT
Server: Jetty(9.2.2.v20140723)
Expires: Tue, 01 Jan 1980 00:00:00 GMT
Pragma: no-cache
Cache-Control: no-cache, must-revalidate
Content-Encoding: gzip
Content-Type: application/json; charset=utf-8
Content-Disposition: attachment
Content-Length: 9684
Via: 1.1 rapla.dhbw-karlsruhe.de
Keep-Alive: timeout=5, max=99
Connection: Keep-Alive
OkHttp-Selected-Protocol: http/1.1
OkHttp-Sent-Millis: 1448356149978
OkHttp-Received-Millis: 1448356149991

����WK�{��J�`k�_��Z����E�p�>3m�WMa�ג�ҵ�p�0��<��
... skipped rest of the body
E��>���S���n 
<--- END HTTP (9684-byte body)
根据Jake Wharton的评论Content-Encoding: gzip标头应告知OkHttp解码主体。

创建RestAdapter的代码如下:

final RestAdapter adapter = new RestAdapter.Builder()
    .setEndpoint(baseUrl)
    .setClient(new OkClient(new OkHttpClient()))
    .setConverter(new GsonConverter(gson))
    .setLogLevel(RestAdapter.LogLevel.FULL)
    .build();
service = adapter.create(RaplaService.class);

Gradle的依赖关系如下:

compile 'com.squareup.retrofit:retrofit:1.9.0'
compile 'com.squareup.okhttp:okhttp:2.6.0'

我的 ServiceInterface 中的方法:

@Headers({
        "Accept-Encoding: gzip, deflate",
        "Content-Type: application/json;charset=utf-8",
        "Accept: application/json"
})
@GET("/events")
List<Event> getEvents(@Header("Authorization") String token, @Query("resources") String resources, @Query("start") String start, @Query("end") String end);

你是怎么获取响应数据的?可能你使用了错误的方法。 - Antoniossss
我在我的ServiceInterface中添加了GET方法。当我使用高级Rest客户端执行相同的请求时,一切都正常工作。 - Simon Tenbeitel
2个回答

67

替换此处:

@Headers({
    "Accept-Encoding: gzip, deflate",
    "Content-Type: application/json;charset=utf-8",
    "Accept: application/json"
})

有了这个:

@Headers({
    "Content-Type: application/json;charset=utf-8",
    "Accept: application/json"
})
当您提供自己的Accept-Encoding标头时,您正在指示OkHttp要进行自己的解压缩。通过省略它,OkHttp将负责添加标题和解压缩。

3
如果我省略了 "Accept-Encoding: gzip, deflate",那么我会得到压缩响应吗? - Hakim
6
是的。如果您省略了“Accept-Encoding”标头,OkHttp将自动添加它自己的标头并代表您进行解压缩。 - Jesse Wilson
2
我在Retrofit 2上也遇到了类似的问题。但是在我的情况下,我向请求构建器中添加了.header("Accept-Encoding", "gzip, deflate") - chubao
5
如果您想禁用OkHttp的自动gzip功能,请添加一个Accept-Encoding头。 - Jesse Wilson
2
@DavidCheung 我其实不必添加这个。根据Jesse Wilson所说,OkHttp会自动添加这个头信息,如果服务器返回的是gzip数据流,它会自动识别并解压缩。如果服务器没有响应gzip请求头,它也不会尝试去解压缩。真聪明。 - Joshua Pinter
显示剩余4条评论

-2
在我的情况下,我注释了client(OkHttpClient client),以下是代码片段。
Retrofit.Builder()
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl(BuildConfig.END_POINT)
            //.client(client)
            .build()

因为我正在使用LoggingInterceptor,所以我认为他不会处理与gzip相关的所有内容。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接