【问题标题】:Streaming upload of a base64 image using retrofit使用改造流式上传 base64 图像
【发布时间】:2017-11-22 14:53:35
【问题描述】:

我有一个上游服务器,它接受使用 REST 提交的图像。提交的图像是类似于此的 JSON 有效负载的一部分

{
  "name": "Blah.jpg",
  "uploader": "user1",
  "image": "<base64.....>"
}

使用此策略适用于小图像,但会在较大图像上产生内存不足错误。

是否可以流式传输图像的 base64 组件?传入诸如迭代器之类的东西,它将用于读取图像块,base64 并将它们直接发送到网络?

【问题讨论】:

  • 是否可以使用POST 直接上传文件,而不是在 JSON 有效负载中包装 blob?
  • 考虑使用 tus 发送图像,它是为它设计的,它允许恢复中断的传输。您当前的解决方案实际上是最糟糕的,请注意 base64 字符串大约比源图像大 1.5 倍。您应该使用 tus 上传图片并在您的 json 中提供 tus 上传 ID
  • 感谢 cmets。我们正在考虑要求我们的上游重新设计 API 并允许我们按照@LyubomyrShaydariv 所说的那样直接发布。嵌入 base64 图像的原因是进行单个 HTTP 调用来传递图像和图像元数据。我们可能需要在新 API 中进行 2 次调用。
  • 请注意 - 我编辑了已接受的答案,结果是最适合我的。我在使用 Android SDK 的 Base64 编码器时遇到了一些问题。

标签: android gson retrofit2 okhttp


【解决方案1】:

没有 Gson 或 Moshi。这两个库都要求字符串在将它们发送到流之前必须在内存中。

【讨论】:

    【解决方案2】:

    我在一个扩展 okhttp3.RequestBody 的类中解决了这个问题:

    private void writeFile(File file, BufferedSink sink) throws IOException {
        byte buf[] = new byte[3000];
        try (FileInputStream fin = new FileInputStream(file)) {
            while (fin.read(buf) >= 0) {
                byte encoded[] = Base64.encodeBase64(buf);
                sink.write(encoded);
            }
        }
    }
    

    它使用 Android 的 android.util.Base64 Apache Commons 的 org.apache.commons.codec.binary.Base64 对缓冲的数据块进行编码。

    我最终分别编写了其他 json 字段,具有足够的粒度,我可以将文件记录准确地插入到我需要的位置。

    编辑:

    正如您在上面的编辑中看到的,我最终通过compile 'commons-codec:commons-codec:1.5' 在我的build.gradle 文件中切换到Apache commons-codec

    我没有时间调查为什么 Android SDK 解决方案不起作用。我按照其他地方的建议尝试了他们的Base64.encode(buf, Base64.NO_WRAP)——据说相当于 Apache Commons 的encodeBase64(byte[])——但这不起作用,因此切换了。

    问题可能出在我们的后端,所以不要仅根据我的帖子排除 Android SDK 的解决方案 - 我只是想添加此注释,以便读者可以在结束。

    【讨论】:

      猜你喜欢
      • 2015-08-22
      • 2016-12-15
      • 2016-10-01
      • 1970-01-01
      • 2018-04-15
      • 2016-10-31
      • 1970-01-01
      • 2015-11-29
      • 2017-01-11
      相关资源
      最近更新 更多