我试图在主体为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的正确方法是什么?
答案 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)
TypedInput
是InputStream
的包装器,它包含用于发出请求的长度和内容类型等元数据。您需要做的就是提供一个实现传递输入流的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);
}
}