如何将InputStream作为Retrofit中请求的主体进行POST?

时间:2014-03-20 18:39:21

标签: rest docker retrofit

我试图在主体为InputStream的情况下进行POST,如下所示:

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

在这种情况下,InputStream来自压缩的tar文件。

POST一个InputStream的正确方法是什么?

5 个答案:

答案 0 :(得分:3)

您可以使用Multipart上传inputStream。

@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

答案 1 :(得分:2)

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

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

  // other methods...
}

请确保根据您要从中传输内容的文件类型为length()mimeType()传递相应的返回值。

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

答案 2 :(得分:2)

根据http://square.github.io/retrofit/的Multipart部分,您希望使用TypedOutput而不是TypedInput。在我们实现了一个TypedOutput类之后,他们的多部分上传示例对我来说很好。

答案 3 :(得分:1)

我在这里提出的唯一解决方案是使用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);

即使我提供了length(),使用我自己的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标头已存在”错误,即使我没有明确设置该标头。

答案 4 :(得分:1)

我的解决方案是实施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);
    }
}