Retrofit 2 Can't Upload A File With Two Additional Separate String Parameters
Solution 1:
I faced similar issue here: Android with Retrofit2 OkHttp3 - Multipart POST Error
I got my problem solved after taking @TommySM suggestion. If is still unclear to you, I think this is the solution:
@Multipart@POST("jobDocuments/upload")
Call<ResponseBody> upload(
@Part MultipartBody.Part file,
@Part("folder") RequestBody folder,
@Part("name") RequestBody name);
Filefile=newFile(fileUri.getPath());
// Assume your file is PNGRequestBodyrequestFile=
RequestBody.create(MediaType.parse("image/png"), file);
MultipartBody.PartfileData=
MultipartBody.Part.createFormData("file", fileName, requestFile);
RequestBodyfolder= RequestBody.create(
MediaType.parse("text/plain"),
"LeadDocuments");
RequestBodyname= RequestBody.create(
MediaType.parse("text/plain"),
fileName);
// finally, execute the request
Call<ResponseBody> call = service.upload(fileData, folder, name);
The important part is to use MediaType.parse("text/plain")
for MediaType
of String parameter (I believe your case is: folder & name parameter), using okhttp3.MultipartBody.FORM
is a mistake.
See these screenshots for the comparison:
1) Problematic POST
2) Correct POST
Solution 2:
So, hope it's no too late, and if so - it might help somebody else :) my 2 cents about this is after having the same problem a while back:
The service definition, using @Part
only (modify field names according to what your server expects)
//Single image MultiPart@Multipart@POST("user/imageupload")
Call<ResponseBody> upload(@Part("userfile") RequestBody file, @Part("userid") RequestBody description);
And for the magic trick, I refer to both parts just as RequestBody
, using the MediaType.parse()
to each one with it's own type, relying on the @Multipart
definition for the request itself, no need for form-data
stuff, the same works for multiple files, and multiple fields:
privatestatic final StringIMG_JPEG = "image/jpeg";
privatestatic final StringTXT_PLAIN = "text/plain";
publicvoiduploadImageMultipart(Uri uri, final CustomEventListener<String> listener)
{
RequestBody fileBody;
RequestBody textBody;
File file = newFile(uri.getPath());
Call<ResponseBody> requestCall;
fileBody = RequestBody.create(okhttp3.MediaType.parse(IMG_JPEG), file);
textBody = RequestBody.create(okhttp3.MediaType.parse(TXT_PLAIN), String.valueOf(SettingsManager.getUserID()));
requestCall = serviceCaller.upload(fileBody, textBody);
requestCall.enqueue(newCallback<ResponseBody>()
{
@OverridepublicvoidonResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> rawResponse)
{
try
{
String response = rawResponse.body().string();
//from here it's your show....
listener.getResult("Got it");
}
catch (Exception e)
{
e.printStackTrace();
}
}
@OverridepublicvoidonFailure(Call<ResponseBody> call, Throwable throwable)
{
}
});
}
(I use a listener to return the callback response to a different part of the app (e.g. a calling activity)).
This definitely sends the file/s and the text field, other problems would probably stem from the server side.
Hope this Helps!
Solution 3:
Interface for Retrofit (API)
publicinterfaceAPI {
StringNAME="name";
StringFOLDER="folder";
@Multipart@POST("/api/jobDocuments/upload")
Call<JsonResponse> uploadFile(
@Part(NAME) String name,
@Part(FOLDER) String folder,
@Part MultipartBody.Part file);
}
Response Class (JsonResponse)
publicclassJsonResponse{
@SerializedName("$id")public String id;
@SerializedName("Message")public String message;
@SerializedName("Path")public String path;
public JsonResponse(String id, String message, String path) {
this.id = id;
this.message = message;
this.path = path;
}
}
API call from application
Retrofit retrofit;
privatevoidpostImage() {
StringURL="http://www.dgheating.com/";
//your file locationFilefile=newFile(Environment.getExternalStorageDirectory() + "/Image.png");
//parametersStringNAME= file.getName();
StringFOLDER="LeadDocuments";
StringFILE="file";
retrofit = newRetrofit.Builder()
.baseUrl(URL)
.addConverterFactory(GsonConverterFactory.create(newGson()))
.build();
APIapi= retrofit.create(API.class);
RequestBodyrequestBody= RequestBody.create(MediaType.parse("multipart/form-data"), file);
MultipartBody.Partpart= MultipartBody.Part.createFormData(FILE, NAME, requestBody);
Call<JsonResponse> call = api.uploadFile(NAME, FOLDER, part);
call.enqueue(newCallback<JsonResponse>() {
@OverridepublicvoidonResponse(Call<JsonResponse> call, Response<JsonResponse> response) {
//response.body() null//response.code() 500//https://github.com/square/retrofit/issues/1321
Converter<ResponseBody, JsonResponse> errorConverter
= retrofit.responseBodyConverter(JsonResponse.class, newAnnotation[0]);
try {
JsonResponsejsonResponse= errorConverter.convert(response.errorBody());
Log.e("error", "id:" + jsonResponse.id); //1
Log.e("error", "message:" + jsonResponse.message); //An error has occurred
Log.e("error", "path:" + jsonResponse.path); //null
} catch (IOException ignored) {
}
}
@OverridepublicvoidonFailure(Call<JsonResponse> call, Throwable t) {
}
});
}
Error in fields, because of any of these server issue
Solution 4:
It looks like your service definition is wrong. Try
@Multipart@POST("jobDocuments/upload")
Call<ResponseBody> upload(@Part("file") MultipartBody.Part file,@Part("folder") RequestBody folder,@Part("name") RequestBody name);
and
RequestBodyfolder=
RequestBody.create(
MediaType.parse("multipart/form-data"), "LeadDocuments");
RequestBodyname=
RequestBody.create(
MediaType.parse("multipart/form-data"), filename);
in your @Background method. This all assumes you are using Retrofit2.
Post a Comment for "Retrofit 2 Can't Upload A File With Two Additional Separate String Parameters"