10

I'm attempting to do a POST with the body being an InputStream with something like this:

@POST("/build")
@Headers("Content-Type: application/tar")
Response build(@Query("t") String tag,
               @Query("q") boolean quiet,
               @Query("nocache") boolean nocache,
               @Body TypedInput inputStream);

In this case the InputStream is from a compressed tar file.

What's the proper way to POST an InputStream?

4

5 回答 5

5

您可以使用上传 inputStream Multipart

@Multipart
@POST("pictures")
suspend fun uploadPicture(
        @Part part: MultipartBody.Part
): NetworkPicture

然后在您的存储库类中:

suspend fun upload(inputStream: InputStream) {
   val part = MultipartBody.Part.createFormData(
         "pic", "myPic", RequestBody.create(
              MediaType.parse("image/*"),
              inputStream.readBytes()
          )
   )
   uploadPicture(part)
}

如果您想了解如何获取图像 Uri,请查看以下答案:https ://stackoverflow.com/a/61592000/10030693

于 2020-05-04T12:08:33.233 回答
2

根据http://square.github.io/retrofit/的 Multipart 部分,您需要使用 TypedOutput 而不是 TypedInput。一旦我实现了 TypedOutput 类,按照他们的分段上传示例对我来说效果很好。

于 2014-04-22T07:57:53.143 回答
2

我在这里想出的唯一解决方案是使用 TypeFile 类:

TypedFile tarTypeFile = new TypedFile("application/tar", myFile);

和接口(这次没有明确设置 Content-Type 标头):

@POST("/build")
Response build(@Query("t") String tag,
               @Query("q") boolean quiet,
               @Query("nocache") boolean nocache,
               @Body TypedInput inputStream);

即使我提供了长度(),使用我自己的 TypedInput 实现也会导致一个模糊的 EOF 异常。

public class TarArchive implements TypedInput {

    private File file;

    public TarArchive(File file) {
        this.file = file;
    }

    public String mimeType() {
        return "application/tar";
    }

    public long length() {
        return this.file.length();
    }

    public InputStream in() throws IOException {
        return new FileInputStream(this.file);
    }
}

此外,在解决此问题时,我尝试使用最新的 Apache Http 客户端而不是 OkHttp,这导致“Content-Length 标头已存在”错误,即使我没有明确设置该标头。

于 2014-03-24T04:26:24.383 回答
2

我的解决方案是实施TypedOutput

public class TypedStream implements TypedOutput{

    private Uri uri;

    public TypedStream(Uri uri){
        this.uri = uri;
    }

    @Override
    public String fileName() {
        return null;
    }

    @Override
    public String mimeType() {
        return getContentResolver().getType(uri);
    }

    @Override
    public long length() {
        return -1;
    }

    @Override
    public void writeTo(OutputStream out) throws IOException {
        Utils.copyStream(getContentResolver().openInputStream(uri), out);
    }
}
于 2015-04-21T10:34:29.463 回答
2

TypedInput是一个包装器,InputStream它具有用于发出请求的长度和内容类型等元数据。您需要做的就是提供一个实现TypedInput传递输入流的类。

class TarFileInput implements TypedInput {
  @Override public InputStream in() {
    return /*your input stream here*/;
  }

  // other methods...
}

确保您传递适当的返回值,length()mimeType()基于您从中流式传输内容的文件类型。

当您调用您的build方法时,您还可以选择将其作为匿名实现传递。

于 2014-03-22T07:40:26.540 回答