修改响应体改造2.2拦截器

2024-01-08

我正在开发一个使用 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());
        }
    }
}

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

这是我从服务收到的回报H4sIAAAAAAAEACspKk0FAI1M/P0EAAAA,解码并解压缩响应,我们有true.

有人知道该怎么做吗?


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

考虑以下测试服务接口:

interface IService {

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

}

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

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();
    }

}

此实现还应该检测内容 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));
    }

}
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);
    }

}

并测试一下:

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);
}

注意getFakeContentInterceptor返回一个总是返回的假拦截器H4sIAAAAAAAEACspKk0FAI1M/P0EAAAA以便baseUrl甚至没有真正的 URL。输出:

true

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

修改响应体改造2.2拦截器 的相关文章

  • “java.io.IOException:连接超时”和“SocketTimeoutException:读取超时”之间有什么区别

    如果我设置一个套接字 SoTimeout 并从中读取 当读取时间超过超时限制时 我会收到 SocketTimeoutException 读取超时 这是我的例子中的堆栈 java net SocketTimeoutException Read
  • Guice 忽略注入构造函数参数上的 @Nullable

    我正在使用 Guice v 3 0 并且有一个值被注入到构造函数中 该值可以为 null 因此我在构造函数中使用 Nullable 来自 javax annotations 注释了该参数 public MyClass Parameter1
  • 使用 WebDriver 单击新打开的选项卡中的链接

    有人可以在这种情况下帮助我吗 场景是 有一个网页 我仅在新选项卡中打开所有指定的链接 现在我尝试单击新打开的选项卡中的任何一个链接 在下面尝试过 但它仅单击主 第一个选项卡中的一个链接 而不是在新选项卡中 new Actions drive
  • Android 中的列表(特别是 RecyclerView 和 CardView)如何工作

    请原谅我问这个问题 但我是 Android 开发新手 尽管我正在尝试了解developer android com 网站上的基础知识 但大多数示例 即使他们说它们是为 Android Studio 构建的 尚未设置为使用 Gradle 因此
  • 改造中的多个队列导致内存不足错误?

    我正在使用retrofit2 做我的项目 当我的呼叫失败时 我再次重复相同的呼叫 重复此 呼叫使我的应用程序强制关闭 当我查看日志时 我得到了错误日志 如下所示 我觉得这是由于同一呼叫的多次排队造成的 所以我在排队之前就这样做了 我打电话给
  • Base36 编码字符串?

    我一直在网上查找 但找不到解决此问题的方法 在 Python Ruby 或 Java 中 如何对以下字符串进行 Base 36 编码 nOrG9Eh0uyeilM8Nnu5pTywj3935kW 5 Ruby 以 36 为基数 s unpa
  • 文本在指定长度后分割,但不要使用 grails 打断单词

    我有一个长字符串 需要将其解析为长度不超过 50 个字符的字符串数组 对我来说 棘手的部分是确保正则表达式找到 50 个字符之前的最后一个空格 以便在字符串之间进行彻底的分隔 因为我不希望单词被切断 public List
  • 为自定义驱动程序创建 GraphicsDevice

    我正在开发一个在嵌入式系统中使用 Java 的项目 我有用于屏幕和触摸输入的驱动程序 以及用于文本输入的虚拟键盘 我的屏幕驱动程序有一个Graphics2D您可以绘制的对象和repaint Rectangle 更新方法 类似地 触摸驱动器能
  • Java中的断点和逐步调试?

    抱歉我的问题名称很奇怪 我不知道如何寻找这个 因为我不知道这些东西是如何称呼的 Visual Studio 中至少有一个功能 您可以单击代码左侧并设置一个大红点的起点 然后运行程序 您可以通过按 f8 或 f5 实际上是不同的 f 来跟踪步
  • Java:从集合中获取第一项

    如果我有一个集合 例如Collection
  • 从直方图计算平均值和百分位数?

    我编写了一个计时器 可以测量任何多线程应用程序中特定代码的性能 在下面的计时器中 它还会在地图中填充花费了 x 毫秒的调用次数 我将使用这张图作为我的直方图的一部分来进行进一步的分析 例如调用花费了这么多毫秒的百分比等等 public st
  • 如何删除日期对象的亚秒部分

    当 SQL 数据类型为时间戳时 java util Date 存储为 2010 09 03 15 33 22 246 如何在存储记录之前将亚秒设置为零 例如 在本例中为 246 最简单的方法是这样的 long time date getTi
  • 在 Clojure 中解压缩 zlib 流

    我有一个二进制文件 其内容由zlib compress在Python上 有没有一种简单的方法可以在Clojure中打开和解压缩它 import zlib import json with open data json zlib wb as
  • Play.application() 的替代方案是什么

    我是 Play 框架的新手 我想读取conf文件夹中的一个文件 所以我用了Play application classloader getResources Data json nextElement getFile 但我知道 play P
  • IntelliJ 组织导入

    IntelliJ 是否具有类似于 Eclipse 中的组织导入功能 我拥有的是一个 Java 文件 其中多个类缺少导入 例子 package com test public class Foo public Map map public J
  • Lombok @Builder 不创建不可变对象?

    在很多网站上 我看到 lombok Builder 可以用来创建不可变的对象 https www baeldung com lombok builder singular https www baeldung com lombok buil
  • 使用 JFreeChart 为两个系列设置不同的 y 轴

    我正在使用 JFreeChart 使用折线图绘制两个数据系列 XYSeries 复杂的因素是 其中一个数据系列的 y 值通常远高于第二个数据系列的 y 值 假设第一个系列的 y 值约为数百万数量级 而第二个数据系列的 y 值约为数百万数量级
  • ArrayList.clear() 和 ArrayList.removeAll() 有什么区别?

    假如说arraylist定义为ArrayList
  • 将对象从手机共享到 Android Wear

    我创建了一个应用程序 在此应用程序中 您拥有包含 2 个字符串 姓名和年龄 和一个位图 头像 的对象 所有内容都保存到 sqlite 数据库中 现在我希望可以在我的智能手表上访问这些对象 所以我想实现的是你可以去启动 启动应用程序并向左和向
  • 即使调整大小,如何获得屏幕的精确中间位置

    好的 这个问题有两部分 当我做一个JFrame 并在其上画一些东西 即使我将宽度设置为 400 并使其在一个项目击中它时 当然 允许项目宽度 它会反弹回来 但由于某种原因 它总是偏离屏幕约 10 个像素 有没有办法解决这个问题 或者我只需要

随机推荐