我有4天的时间,试图在Android中使用Retrofit 1.8.0进行多部分请求,并取得任何成功。我的界面看起来像这样
@Multipart
@POST("/posts/add.json")
void addComment(
@Part("id") String id,
@Part("post[body]") String body,
@Part("post[attachment]") TypedFile attachment,
Callback<Map<String, String>> callback );
但是,在服务器端,我收到以下
Parameters: {"id"=># <File:/var/folders/z0/0ggjvvfj4t1fdsvbxf3lc9pw0000gn/T/RackMultipart9853-0>, "post"=>{"body"=>#<File:/var/folders/z0/0ggjvvfj4t1fdsvbxf3lc9pw0000gn/T/RackMultipart9853-1>, "attachment"=>#<File:/var/folders/z0/0ggjvvfj4t1fdsvbxf3lc9pw0000gn/T/RackMultipart9853-2>}, "controller"=>"posts", "action"=>"add", "format"=>"json"}
正如你所看到的,文件部分是在每个部分发送它但是我错过了参数的id值和post [body]
这就是Retrofit试图发送的内容
02-06 15:01:16.213 32545-822/com.myapp D/Retrofit﹕ --fe41634b-6826-4ee4-95cb-65efb0ca66c2
Content-Disposition: form-data; name="id"
Content-Type: text/plain; charset=UTF-8
Content-Length: 3
Content-Transfer-Encoding: binary
189
--fe41634b-6826-4ee4-95cb-65efb0ca66c2
Content-Disposition: form-data; name="post[body]"
Content-Type: text/plain; charset=UTF-8
Content-Length: 4
Content-Transfer-Encoding: binary
test
--fe41634b-6826-4ee4-95cb-65efb0ca66c2
Content-Disposition: form-data; name="post[attachment]"; filename="IMG_20140203_144358.jpg"
Content-Type: image/jpg
Content-Length: 1615460
Content-Transfer-Encoding: binary
����/�Exif����MM��*���������
这是HttpMime库在Multipart中发送的内容,区别在于对于Retrofit的“Content-Transfer-Encoding”标头
Content-Disposition: form-data; name="id"
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 8bit
Content-Disposition: form-data; name=“post[body]"
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 8bit
Content-Disposition: form-data; name=“post[attachment]"; filename="images.jpg"
Content-Type: image/jpg
Content-Transfer-Encoding: binary
有任何线索吗?提前致谢
------------------------------- SOLUTION ------------ ----------------------
最后,我解决了这个问题,实际上我的回答非常接近@lazypig,这是一个很好的指导方针
我唯一改变的是他的班级“ByteArrayTypedOutput”
我创建了一个名为“MultipartTypedOutputCustom”http://pastie.org/10549360
的类这就是它现在看起来我的界面
“PostsRetrofitAPI.java”类
@POST("/posts/add.json")
void addComment(@Body MultipartTypedOutputCustom parts,
Callback<Map<String, String>> callback);
“PostsService.java” 类
//Properties
private PostsRetrofitAPI mApi;
...
@Override
public void addComment(ServiceResponseHandler<Map<String, String>> handler, String id, String body, TypedFile attachment) {
MultipartTypedOutputCustom parts = new MultipartTypedOutputCustom();
parts.addPart("id", new TypedString(id));
parts.addPart("post[body]", new TypedString(body));
parts.addPart("post[attachment]", attachment);
objectRetrofitCallback= new ObjectRetrofitCallback(handler, ServerError.class, ClientError.class);
mApi.addComment(parts, objectRetrofitCallback);
}
答案 0 :(得分:3)
如果您在http://square.github.io/retrofit/上看到示例,则“id”和“part [body]”参数的对象类型必须是TypedString而不是String。 TypedString设置适当的MIME类型并转换为字节:
https://github.com/square/retrofit/blob/master/retrofit/src/main/java/retrofit/mime/TypedString.java
答案 1 :(得分:1)
我这样做是为了接口
interface MultipartFormDataService {
@POST("/{uploadPath}")
void multipartFormDataSend(
@EncodedPath("uploadPath") String uploadPath,
@Body MultipartTypedOutput multipartTypedOutput,
Callback<String> cb);
}
然后,当我打电话给它时,它看起来像这样
// creating the Multipart body using retrofit
MultipartTypedOutput multipartTypedOutput = new MultipartTypedOutput();
TypedString idParam = new TypedString("[ID Value]")
TypedString bodyParam = new TypedString("[Body text]")
ByteArrayTypedOutput byteMultipartTypedOut = new ByteArrayTypedOutput(bytes)
// add parts
multipartTypedOutput.addPart("id", idParam);
multipartTypedOutput.addPart("body", bodyParam);
multipartTypedOutput.addPart("attachment", extraParamTypedString);
// send
multipartService.multipartFormDataSend(
"[TARGET URL]",
multipartTypedOutput,
aCallback);
我的ByteArrayTypedOutput很简单
public class ByteArrayTypedOutput implements TypedOutput {
private MultipartFormMetadata metadata;
private byte[] imageData;
public ByteArrayTypedOutput(MultipartFormMetadata metadata, byte[] imageData)
this.metadata = metadata;
this.imageData = imageData;
}
@Override
public String fileName() {
return metadata.fileName;
}
@Override
public String mimeType() {
return metadata.fileMimeType;
}
@Override
public long length() {
return imageData.length;
}
@Override
public void writeTo(OutputStream outputStream) throws IOException {
outputStream.write(imageData);
}
}
答案 2 :(得分:0)
今天我有类似的问题发送文件和一些字段,这是我的解决方案
我的界面,TypedFile是一个Retrofit类
@Multipart
@POST("/api/Media/add")
void addMedia(@Part("file") TypedFile photo,
@Part("type") String type,
@Part("name") String name,
@Part("description") String description,
Callback<com.yourcompany.pojo.Media> callback);
在活动中
profileImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent galleryIntent = new Intent(
Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(galleryIntent , RESULT_GALLERY );
}
});
然后
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case RESULT_GALLERY :
if (null != data) {
imageUri = data.getData();
String selectedImagePath = null;
Uri selectedImageUri = data.getData();
Cursor cursor = activity.getContentResolver().query(selectedImageUri, null, null,
null, null);
if (cursor == null) {
selectedImagePath = imageUri.getPath();
} else {
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
selectedImagePath = cursor.getString(idx);
}
File file = new File(selectedImagePath);
waiter.setVisibility(View.VISIBLE);
_YOUR_APP_._YOUR_INTERFACE_.addMedia(new TypedFile("image/*", file), "avatar", "avatar", "avatar", new Callback<Media>() {
@Override
public void success(Media media, Response response) {
}
@Override
public void failure(RetrofitError error) {
}
});
}
break;
default:
break;
}
}
媒体课很容易回答
public class Media {
@Expose
private int[] data;
/**
*
* @return
* The data
*/
public int getData() {
return data[0];
}
/**
*
* @param data
* The data
*/
public void setData(int[] data) {
this.data = data;
}
}