我正在尝试使用Retrofit 2.0对服务器进行HTTP POST
MediaType MEDIA_TYPE_TEXT = MediaType.parse("text/plain"); MediaType MEDIA_TYPE_IMAGE = MediaType.parse("image/*"); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); imageBitmap.compress(Bitmap.CompressFormat.JPEG,90,byteArrayOutputStream); profilePictureByte = byteArrayOutputStream.toByteArray(); Callcall = ServiceAPI.updateProfile( RequestBody.create(MEDIA_TYPE_TEXT, emailString), RequestBody.create(MEDIA_TYPE_IMAGE, profilePictureByte)); call.enqueue();
服务器返回错误,指出文件无效.
这很奇怪,因为我试图在iOS上使用相同的格式上传相同的文件(使用其他库),但它上传成功.
我想知道使用Retrofit 2.0上传图像的正确方法是什么?
在上传之前我应该先将它保存到磁盘吗?
谢谢!
PS:我已经将改造用于其他不包含图像的Multipart请求,并且已成功完成.问题是当我试图在主体中包含一个字节时.
我正在强调1.9和2.0中的解决方案,因为它对某些人有用
在1.9
,我认为更好的解决方案是将文件保存到磁盘并将其用作类型文件,如:
(我不知道你的服务器端实现)有一个类似于此的API接口方法
@POST("/en/Api/Results/UploadFile") void UploadFile(@Part("file")TypedFile file,@Part("folder")String folder,Callbackcallback);
并使用它
TypedFile file = new TypedFile("multipart/form-data", new File(path));
API接口:
public interface ApiInterface { @Multipart @POST("/api/Accounts/editaccount") CalleditUser (@Header("Authorization") String authorization, @Part("file\"; filename=\"pp.png\" ") RequestBody file , @Part("FirstName") RequestBody fname, @Part("Id") RequestBody id); }
使用它像:
File file = new File(imageUri.getPath()); RequestBody fbody = RequestBody.create(MediaType.parse("image/*"), file); RequestBody name = RequestBody.create(MediaType.parse("text/plain"), firstNameField.getText().toString()); RequestBody id = RequestBody.create(MediaType.parse("text/plain"), AZUtils.getUserId(this)); Callcall = client.editUser(AZUtils.getToken(this), fbody, name, id); call.enqueue(new Callback () { @Override public void onResponse(retrofit.Response response, Retrofit retrofit) { AZUtils.printObject(response.body()); } @Override public void onFailure(Throwable t) { t.printStackTrace(); } });
有一种正确的方法可以上传名称为Retrofit 2的文件,没有任何黑客攻击:
定义API接口:
@Multipart @POST("uploadAttachment") CalluploadAttachment(@Part MultipartBody.Part filePart); // You can add other parameters too
像这样上传文件:
File file = // initialize file here MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", file.getName(), RequestBody.create(MediaType.parse("image/*"), file)); Callcall = api.uploadAttachment(filePart);
这仅演示了文件上传,您还可以使用@Part
注释在同一方法中添加其他参数.
我为我的注册用户使用了Retrofit 2.0,从注册帐户发送multipart/form文件图像和文本
在我的RegisterActivity中,使用AsyncTask
//AsyncTask private class Register extends AsyncTask{ @Override protected void onPreExecute() {..} @Override protected String doInBackground(String... params) { new com.tequilasoft.mesasderegalos.dbo.Register().register(txtNombres, selectedImagePath, txtEmail, txtPassword); responseMensaje = StaticValues.mensaje ; mensajeCodigo = StaticValues.mensajeCodigo; return String.valueOf(StaticValues.code); } @Override protected void onPostExecute(String codeResult) {..}
在我的Register.java类中,使用Retrofit进行同步调用
import android.util.Log; import com.tequilasoft.mesasderegalos.interfaces.RegisterService; import com.tequilasoft.mesasderegalos.utils.StaticValues; import com.tequilasoft.mesasderegalos.utils.Utilities; import java.io.File; import okhttp3.MediaType; import okhttp3.MultipartBody; import okhttp3.RequestBody; import okhttp3.ResponseBody; import retrofit2.Call; import retrofit2.Response; /**Created by sam on 2/09/16.*/ public class Register { public void register(String nombres, String selectedImagePath, String email, String password){ try { // create upload service client RegisterService service = ServiceGenerator.createUser(RegisterService.class); // add another part within the multipart request RequestBody requestEmail = RequestBody.create( MediaType.parse("multipart/form-data"), email); // add another part within the multipart request RequestBody requestPassword = RequestBody.create( MediaType.parse("multipart/form-data"), password); // add another part within the multipart request RequestBody requestNombres = RequestBody.create( MediaType.parse("multipart/form-data"), nombres); MultipartBody.Part imagenPerfil = null; if(selectedImagePath!=null){ File file = new File(selectedImagePath); Log.i("Register","Nombre del archivo "+file.getName()); // create RequestBody instance from file RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file); // MultipartBody.Part is used to send also the actual file name imagenPerfil = MultipartBody.Part.createFormData("imagenPerfil", file.getName(), requestFile); } // finally, execute the request Callcall = service.registerUser(imagenPerfil, requestEmail,requestPassword,requestNombres); Response bodyResponse = call.execute(); StaticValues.code = bodyResponse.code(); StaticValues.mensaje = bodyResponse.message(); ResponseBody errorBody = bodyResponse.errorBody(); StaticValues.mensajeCodigo = errorBody==null ?null :Utilities.mensajeCodigoDeLaRespuestaJSON(bodyResponse.errorBody().byteStream()); Log.i("Register","Code "+StaticValues.code); Log.i("Register","mensaje "+StaticValues.mensaje); Log.i("Register","mensajeCodigo "+StaticValues.mensaje); } catch (Exception e){ e.printStackTrace(); } } }
在RegisterService的界面中
public interface RegisterService { @Multipart @POST(StaticValues.REGISTER) CallregisterUser(@Part MultipartBody.Part image, @Part("email") RequestBody email, @Part("password") RequestBody password, @Part("nombre") RequestBody nombre ); }
对于Utilities解析的InputStream响应
public class Utilities { public static String mensajeCodigoDeLaRespuestaJSON(InputStream inputStream){ String mensajeCodigo = null; try { BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream, "iso-8859-1"), 8); StringBuilder sb = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { sb.append(line).append("\n"); } inputStream.close(); mensajeCodigo = sb.toString(); } catch (Exception e) { Log.e("Buffer Error", "Error converting result " + e.toString()); } return mensajeCodigo; } }
更新Retrofit2.0中图像文件上传的代码
public interface ApiInterface { @Multipart @POST("user/signup") CallupdateProfilePhotoProcess(@Part("email") RequestBody email, @Part("password") RequestBody password, @Part("profile_pic\"; filename=\"pp.png\" ") RequestBody file); }
更改MediaType.parse("image/*")
到MediaType.parse("image/jpeg")
RequestBody reqFile = RequestBody.create(MediaType.parse("image/jpeg"), file); RequestBody email = RequestBody.create(MediaType.parse("text/plain"), "upload_test4@gmail.com"); RequestBody password = RequestBody.create(MediaType.parse("text/plain"), "123456789"); Callcall = apiService.updateProfilePhotoProcess(email,password,reqFile); call.enqueue(new Callback () { @Override public void onResponse(Call call, Response response) { String TAG = response.body().toString(); UserModelResponse userModelResponse = response.body(); UserModel userModel = userModelResponse.getUserModel(); Log.d("MainActivity","user image = "+userModel.getProfilePic()); } @Override public void onFailure(Call call, Throwable t) { Toast.makeText(MainActivity.this,""+TAG,Toast.LENGTH_LONG).show(); } });
添加@insomniac给出的答案.您可以创建一个Map
用于放置RequestBody
包含图像的参数.
接口代码
public interface ApiInterface { @Multipart @POST("/api/Accounts/editaccount") CalleditUser (@Header("Authorization") String authorization, @PartMap Map map); }
Java类的代码
File file = new File(imageUri.getPath()); RequestBody fbody = RequestBody.create(MediaType.parse("image/*"), file); RequestBody name = RequestBody.create(MediaType.parse("text/plain"), firstNameField.getText().toString()); RequestBody id = RequestBody.create(MediaType.parse("text/plain"), AZUtils.getUserId(this)); Mapmap = new HashMap<>(); map.put("file\"; filename=\"pp.png\" ", fbody); map.put("FirstName", name); map.put("Id", id); Call call = client.editUser(AZUtils.getToken(this), map); call.enqueue(new Callback () { @Override public void onResponse(retrofit.Response response, Retrofit retrofit) { AZUtils.printObject(response.body()); } @Override public void onFailure(Throwable t) { t.printStackTrace(); } });
因此,这是完成任务的非常简单的方法。您需要按照以下步骤操作:-
1.第一步
public interface APIService { @Multipart @POST("upload") Callupload( @Part("item") RequestBody description, @Part("imageNumber") RequestBody description, @Part MultipartBody.Part imageFile ); }
您需要按进行整个通话@Multipart request
。item
并且image number
是被包裹在刚刚绳体RequestBody
。我们使用的MultipartBody.Part class
,使我们除了发送带有请求的二进制文件数据外,还可以发送实际的文件名
2.第二步
File file = (File) params[0]; RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file); MultipartBody.Part body =MultipartBody.Part.createFormData("Image", file.getName(), requestBody); RequestBody ItemId = RequestBody.create(okhttp3.MultipartBody.FORM, "22"); RequestBody ImageNumber = RequestBody.create(okhttp3.MultipartBody.FORM,"1"); final Callrequest = apiService.uploadItemImage(body, ItemId,ImageNumber);
现在您拥有了image path
,您需要转换为file
.Now转换file
为RequestBody
using方法RequestBody.create(MediaType.parse("multipart/form-data"), file)
。现在,您需要将转换RequestBody requestFile
为MultipartBody.Part
using方法MultipartBody.Part.createFormData("Image", file.getName(), requestBody);
。
ImageNumber
并且ItemId
是我需要发送到服务器的另一个数据,因此我也将两者都放入了RequestBody
。
欲了解更多信息