Retrofit multpart上传文件
在最初的http协议中,没有定义上传文件的Method,为了实现这个功能,http协议组改造了post请求,添加了一种post规范,设定这种规范的Content-Type为multipart/form-data;boundary= b o u n d , 其 中 {bound},其中 bound,其中{bound}是定义的分隔符,用于分割各项内容(文件,key-value对),不然服务器无法正确识别各项内容。post body里需要用到,尽量保证随机唯一。
-
在retrofit中:
- @retrofit2.http.Multipart: 标记一个请求是multipart/form-data类型,需要和@retrofit2.http.POST一同使用,并且方法参数必须是@retrofit2.http.Part注解。
- @retrofit2.http.Part: 代表Multipart里的一项数据,即用${bound}分隔的内容块。
-
在okhttp3中:
- okhttp3.MultipartBody :multipart/form-data 的抽象封装,继承okhttp3.RequestBody
- okhttp3.MultipartBody.Part:multipart/form-data里的一项数据。
文件上传
单个文件上传
@Multipart
@POST("upload")
Call<ResponseBody> uploadOneFile(@Part MultipartBody.Part body);
调用的使用MultipartBody.Part来构造一个Part对象参数
String name = etFileName.getText().toString().trim();
name = TextUtils.isEmpty(name) ? "1.png" : name;
String path = Environment.getExternalStorageDirectory() + File.separator + name;
File file = new File(path);
RequestBody fileRQ = RequestBody.create(MediaType.parse("image/*"), file);
MultipartBody.Part part MultipartBody.Part.createFormData("picture", file.getName(), fileRQ);
Call<ResponseBody> uploadCall = downloadService.uploadOneFile(part);
多文件上传
使用@PartMap实现
@Multipart
@POST("upload")
Call<ResponseBody> uploadFiles(@PartMap Map<String, RequestBody> map);
调用方法
RequestBody fb = RequestBody.create(MediaType.parse("text/plain"), "hello,retrofit");
RequestBody fileTwo = RequestBody.create(MediaType.parse("image/*"), new File(Environment.getExternalStorageDirectory()
+ file.separator + "original.png"));
Map<String, RequestBody> map = new HashMap<>();
//这里的key必须这么写,否则服务端无法识别
map.put("file\"; filename=\""+ file.getName(), fileRQ);
map.put("file\"; filename=\""+ "2.png", fileTwo);
Call<ResponseBody> uploadCall = downloadService.uploadFiles(map);
文件和参数混合上传
接口定义,注意这个时候没有@Multipart
当我们采用这种方式上传的时候,不能再接口上加上@Multipart的注解,否者会报错
@POST("api/community/room/person/face/reg")
Observable<JSONObject> updateFace(@Header("Authorization") String header,@Body RequestBody requestBody);
调用
File file = new File(face_url);
RequestBody fileRQ = RequestBody.create(MediaType.parse("multipart/form-data"), file);
RequestBody body=new MultipartBody.Builder()
.addFormDataPart("params1","params1")
.addFormDataPart("params2","params2")
.addFormDataPart("params3","params3")
.addFormDataPart("file",file.getName(),fileRQ)
.build();
RetrofitConfig.createService().updateFace(RetrofitConfig.getHeaders(token),body)
或者使用@Multipart注解(此混合上传的方式未成功,建议使用上面的方式)
@Multipart
@POST("upload")
Call<ResponseBody> uploadFile(@Part("body") RequestBody body, @Part MultipartBody.Part file);
调用
MultipartBody.Part part = MultipartBody.Part.createFormData("picture", file.getName(), fileRQ);
RequestBody fb =RequestBody.create(MediaType.parse("text/plain"), "hello,retrofit");
Call<ResponseBody> uploadCall = downloadService.uploadFile(fb,part);
注意:
1.如果在上传文件的时候,定义:
@Multipart
@POST("upload")
Call<ResponseBody> uploadOneFile(@Part RequestBody file);
显示下面的错误:
@Part annotation must supply a name or use MultipartBody.Part parameter type. (parameter #1)
2.如果@Part加上参数,并RequestBody作为参数,上传文件,服务端识别不出来这是一个文件,会当做一个参数上传的例子
@Multipart
@POST("upload")
Call<ResponseBody> uploadOneFile(@Part("file") RequestBody file);
3.如果使用MultipartBody.Part作为参数,又加上了名字
uploadOneFile(@Part("file") MultipartBody.Part file)
则会显示下面的错误
@Part parameters using the MultipartBody.Part must not include a part name in the annotation