改造:如何在没有Content-Encoding的情况下解析GZIP的响应:gzip标头

its*_*bal 5 gzip okhttp retrofit2 okhttp3

我正在尝试处理GZIP的服务器响应.响应带有标题

Content-Type: application/x-gzip
Run Code Online (Sandbox Code Playgroud)

但没有标题

Content-Encoding: gzip
Run Code Online (Sandbox Code Playgroud)

如果我使用代理添加该头,则响应得到解析就好了.我对服务器没有任何控制权,所以我无法添加标题.

我可以强制将Retrofit视为GZIP内容吗?有没有更好的办法?服务器的URL是:http: //crowdtorch.cms.s3.amazonaws.com/4474/Updates/update-1.xml

its*_*bal 8

我想到了.我们的想法是添加一个自定义拦截器,它将采用尚未解压缩的响应,然后"手动"解压缩 - 执行OkHttp基于Content-Encoding标头自动执行的操作,但不需要该标头.

就像dis:

    OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder()
            .addInterceptor(new UnzippingInterceptor());
    OkHttpClient client = clientBuilder.build();
Run Code Online (Sandbox Code Playgroud)

拦截器就像dis:

private class UnzippingInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Response response = chain.proceed(chain.request());
        return unzip(response);
    }
}
Run Code Online (Sandbox Code Playgroud)

解压缩功能就像dis:

    // copied from okhttp3.internal.http.HttpEngine (because is private)
private Response unzip(final Response response) throws IOException {

    if (response.body() == null) {
        return response;
    }

    GzipSource responseBody = new GzipSource(response.body().source());
    Headers strippedHeaders = response.headers().newBuilder()
            .removeAll("Content-Encoding")
            .removeAll("Content-Length")
            .build();
    return response.newBuilder()
            .headers(strippedHeaders)
            .body(new RealResponseBody(strippedHeaders, Okio.buffer(responseBody)))
            .build();
}
Run Code Online (Sandbox Code Playgroud)


Abh*_*kar 4

有比重新发明轮子更好的方法。只需自己添加Content-Encoding标题即可。

.addNetworkInterceptor((Interceptor.Chain chain) -> {
    Request req = chain.request();
    Headers.Builder headersBuilder = req.headers().newBuilder();

    String credential = Credentials.basic(...);
    headersBuilder.set("Authorization", credential);

    Response res = chain.proceed(req.newBuilder().headers(headersBuilder.build()).build());

    return res.newBuilder()
        .header("Content-Encoding", "gzip")
        .header("Content-Type", ""application/json")
        .build();
})
Run Code Online (Sandbox Code Playgroud)

事实上,您的代码是使用内部代码(如com.sunJDK 中的包)的弊端的典型示例。RealResponseBody不再有那个构造函数了。