修改响应体改造2.2拦截器

jac*_*car 2 java base64 gzip interceptor retrofit

我正在使用Retrofit 2开发一个应用程序以请求API。该API位于ASP.NET中,并且使用GZip压缩并编码为Base64,如以下代码所示:

private static string Compress(string conteudo)
{
    Encoding encoding = Encoding.UTF8;
    byte[] raw = encoding.GetBytes(conteudo);

    using (var memory = new MemoryStream())
    {
        using (GZipStream gzip = new GZipStream(memory, CompressionMode.Compress, true))
        {
            gzip.Write(raw, 0, raw.Length);
        }
        return Convert.ToBase64String(memory.ToArray());
    }
}

private static string Decompress(string conteudo)
{
    Encoding encoding = Encoding.UTF8;
    var gzip = Convert.FromBase64String(conteudo);

    using (GZipStream stream = new GZipStream(new MemoryStream(gzip), CompressionMode.Decompress))
    {
        int size = gzip.Length;
        byte[] buffer = new byte[size];
        using (MemoryStream memory = new MemoryStream())
        {
            int count = 0;
            do
            {
                count = stream.Read(buffer, 0, size);
                if (count > 0)
                {
                    memory.Write(buffer, 0, count);
                }
            }
            while (count > 0);
            return encoding.GetString(memory.ToArray());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,我需要在Android应用中执行的操作是从Retrofit获取响应,从Base64解码并解压缩。我尝试使用进行操作Interceptor,但没有成功。

这是我从服务中收到H4sIAAAAAAAEACspKk0FAI1M/P0EAAAA的对我们进行解码和解压缩响应的返回true

有人知道怎么做吗?

Lyu*_*riv 7

这简单。下面的代码使用Google Guava来解码Base64字符流,并使用Google Gson反序列化JSON内容。

考虑以下测试服务接口:

interface IService {

    @GET("/")
    Call<String> get();

}
Run Code Online (Sandbox Code Playgroud)

现在,您可以使用模板方法设计模式来实现拦截器响应输入流转换器基础:

abstract class AbstractTransformingDecodingInterceptor
        implements Interceptor {

    protected abstract InputStream transformInputStream(InputStream inputStream)
            throws IOException;

    @Override
    @SuppressWarnings("resource")
    public final Response intercept(final Chain chain)
            throws IOException {
        final Request request = chain.request();
        final Response response = chain.proceed(request);
        final ResponseBody body = response.body();
        return response.newBuilder()
                .body(ResponseBody.create(
                        body.contentType(),
                        body.contentLength(),
                        Okio.buffer(Okio.source(transformInputStream(body.byteStream())))
                ))
                .build();
    }

}
Run Code Online (Sandbox Code Playgroud)

此实现还应该检测内容MIME类型,以免进行错误的转换,但是您可以自己轻松实现它。因此,这也是Base64和GZip的两个转换拦截器:

final class Base64DecodingInterceptor
        extends AbstractTransformingDecodingInterceptor {

    private static final Interceptor base64DecodingInterceptor = new Base64DecodingInterceptor();

    private Base64DecodingInterceptor() {
    }

    static Interceptor getBase64DecodingInterceptor() {
        return base64DecodingInterceptor;
    }

    @Override
    protected InputStream transformInputStream(final InputStream inputStream) {
        return BaseEncoding.base64().decodingStream(new InputStreamReader(inputStream));
    }

}
Run Code Online (Sandbox Code Playgroud)
final class GzipDecodingInterceptor
        extends AbstractTransformingDecodingInterceptor {

    private static final Interceptor gzipDecodingInterceptor = new GzipDecodingInterceptor();

    private GzipDecodingInterceptor() {
    }

    static Interceptor getGzipDecodingInterceptor() {
        return gzipDecodingInterceptor;
    }

    @Override
    protected InputStream transformInputStream(final InputStream inputStream)
            throws IOException {
        return new GZIPInputStream(inputStream);
    }

}
Run Code Online (Sandbox Code Playgroud)

并测试一下:

private static final OkHttpClient okHttpClient = new OkHttpClient.Builder()
        .addInterceptor(getGzipDecodingInterceptor())
        .addInterceptor(getBase64DecodingInterceptor())
        .addInterceptor(getFakeContentInterceptor())
        .build();

private static final Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://whatever")
        .client(okHttpClient)
        .addConverterFactory(GsonConverterFactory.create())
        .build();

private static final IService service = retrofit.create(IService.class);

public static void main(final String... args)
        throws IOException {
    final String body = service.get().execute().body();
    System.out.println(body);
}
Run Code Online (Sandbox Code Playgroud)

请注意,getFakeContentInterceptor返回的是一个伪造的拦截器,该拦截器总是返回,H4sIAAAAAAAEACspKk0FAI1M/P0EAAAA因此baseUrl甚至没有真实的URL。输出:

真正