How to upload a file using multipart/form-data upload in Retrofit 2.0, I am unable to upload and there is no proper documentation anywhere on uploading file using retrofit 2.0, I followed the docs in retrofit website but I was not able to make it work.
All the examples I see used TypedFile. It is not clear how to use RequestBody. Please post sample code.
Same as v1. Use the Multipart annotation on the method and Part annotation
on parameters.
On Mon, Sep 7, 2015, 7:06 AM Vivek Kiran [email protected] wrote:
How to upload a file using multipart upload in Retrofit 2.0
—
Reply to this email directly or view it on GitHub
https://github.com/square/retrofit/issues/1063.
Oh for the file itself, use RequestBody for the type.
On Mon, Sep 7, 2015, 10:50 AM Jake Wharton [email protected] wrote:
Same as v1. Use the Multipart annotation on the method and Part annotation
on parameters.On Mon, Sep 7, 2015, 7:06 AM Vivek Kiran [email protected] wrote:
How to upload a file using multipart upload in Retrofit 2.0
—
Reply to this email directly or view it on GitHub
https://github.com/square/retrofit/issues/1063.
Hi,
I am getting following exception while executing:
@Headers("User-Agent: " + Constants.CLIENT_NAME)
@Multipart
@POST(Constants.Urls.SYNC_URL)
Call<BaseResponseDto> uploadFile(@Part("file") RequestBody song, @Part("file_path") String fileName, @Part("method") String method, @Part("user_id") String userId, @Part("token") String token);
09-07 17:49:38.072 13562-13582/? W/EGL_emulation﹕ eglSurfaceAttrib not implemented
java.lang.IllegalStateException: JSON must start with an array or an object.
at com.google.gson.stream.JsonWriter.beforeValue(JsonWriter.java:609)
at com.google.gson.stream.JsonWriter.value(JsonWriter.java:418)
at com.google.gson.internal.bind.TypeAdapters$13.write(TypeAdapters.java:362)
at com.google.gson.internal.bind.TypeAdapters$13.write(TypeAdapters.java:346)
at com.google.gson.TypeAdapter.toJson(TypeAdapter.java:142)
at retrofit.GsonConverter.toBody(GsonConverter.java:55)
at retrofit.RequestBuilderAction$Part.perform(RequestBuilderAction.java:204)
at retrofit.RequestFactory.create(RequestFactory.java:62)
at retrofit.OkHttpCall.createRawCall(OkHttpCall.java:116)
at retrofit.OkHttpCall.execute(OkHttpCall.java:106)
at retrofit.ExecutorCallAdapterFactory$ExecutorCallbackCall.execute(ExecutorCallAdapterFactory.java:59)
at com.ibroadcast.mediasynclite.api.upload.UploadRunnable.run(UploadRunnable.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Everything worked until I migrated to Retrofit 2.0. Is anything wrong with my request?
Thanks in advance.
Retrofit 2 is not released so I'll assume you mean the beta1. This is
already fixed in master and will be in the next release.
On Mon, Sep 7, 2015, 6:06 PM Vadim Oleynik [email protected] wrote:
Hi,
I am getting following exception while executing:
@Headers("User-Agent: " + Constants.CLIENT_NAME)
@Multipart
@POST(Constants.Urls.SYNC_URL)
CalluploadFile(@Part("file") RequestBody song, @Part("file_path") String fileName, @Part("method") String method, @Part("user_id") String userId, @Part("token") String token); 09-07 17:49:38.072 13562-13582/? W/EGL_emulation﹕ eglSurfaceAttrib not
implementedjava.lang.IllegalStateException: JSON must start with an array or an
object.
at com.google.gson.stream.JsonWriter.beforeValue(JsonWriter.java:609)
at com.google.gson.stream.JsonWriter.value(JsonWriter.java:418)
at
com.google.gson.internal.bind.TypeAdapters$13.write(TypeAdapters.java:362)
at
com.google.gson.internal.bind.TypeAdapters$13.write(TypeAdapters.java:346)
at com.google.gson.TypeAdapter.toJson(TypeAdapter.java:142)
at retrofit.GsonConverter.toBody(GsonConverter.java:55)
at
retrofit.RequestBuilderAction$Part.perform(RequestBuilderAction.java:204)
at retrofit.RequestFactory.create(RequestFactory.java:62)
at retrofit.OkHttpCall.createRawCall(OkHttpCall.java:116)
at retrofit.OkHttpCall.execute(OkHttpCall.java:106)
at
retrofit.ExecutorCallAdapterFactory$ExecutorCallbackCall.execute(ExecutorCallAdapterFactory.java:59)
at
com.ibroadcast.mediasynclite.api.upload.UploadRunnable.run(UploadRunnable.java:49)
at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)Everything worked until I migrated to Retrofit 2.0. Is anything wrong with
my request?Thanks in advance.
—
Reply to this email directly or view it on GitHub
https://github.com/square/retrofit/issues/1063#issuecomment-138384216.
Use the latest snapshot for the fix, or wait until the next release.
Actually, I have downloaded the latest version using:
But issue still exists :(
On Mon, Sep 7, 2015 at 7:25 PM, Jake Wharton [email protected]
wrote:
Closed #1063 https://github.com/square/retrofit/issues/1063.
—
Reply to this email directly or view it on GitHub
https://github.com/square/retrofit/issues/1063#event-403092158.
I have also tried the same as VadimWelldone, and experienced no change or fix of the problem.
Edit: After some messing around this seems to be a problem with multi parts and not the use of RequestBody's
Thanks Ashig. I'll try it a little bit later. Hope your approach will
resolve existing issue.
On Mon, Sep 14, 2015, 7:30 AM Ashiq Uz Zoha [email protected]
wrote:
I have a tested solution about this issue. You'll need to send to all
parameters as RequestBody.@Multipart
@POST("/api/Accounts/addaccount")
Callsignup(
@Part("FirstName") RequestBody fname,
@Part("LastName") RequestBody lname,
@Part("email") RequestBody email,
@Part("password") RequestBody password,
@Part("username") RequestBody uname,
@Part("Newsletter") RequestBody nl
);And we need to call the method like this...
Call
call = client.signup(
RequestBody.create(MediaType.parse("text"),firstNameField.getText().toString().getBytes()),
RequestBody.create(MediaType.parse("text"), lastNameField.getText().toString().getBytes()),
RequestBody.create(MediaType.parse("text"), emailField.getText().toString().getBytes()),
RequestBody.create(MediaType.parse("text"), passwordField.getText().toString().getBytes()),
RequestBody.create(MediaType.parse("text"), userNameField.getText().toString().getBytes()),
RequestBody.create(MediaType.parse("text"), toByteArray(bits))
);Hope it helps.
—
Reply to this email directly or view it on GitHub
https://github.com/square/retrofit/issues/1063#issuecomment-140044962.
Hello @VadimWelldone , I deleted that comment because after spending some more time, I noticed that for doing that approach I get status code 200 as response (may be because of my backend) but those parameters don't actually gets stored to my database correctly. So, thats not actually a solution.
But here is my real finding why. I am almost sure that, the Multipart request (file upload) is from okhttp. Retrofit probably has nothing to do with it. My Multipart request has both text and image data. When I pack all my text data into a PartMap and use @PartMap in Retrofit, these things gets Posted to backend correctly.
But there's problem with image or file upload. Retrofit 2.0 tells to use okhttp RequestBody to send file. I tried that both with Retrofit and Standalone okhttp library. None of my attempt could successfully upload the file to backend. So, I guess, this problem is from okhttp and we know Retrofit 2.0 uses it as default client. And I confirm that my API is fine as I can POST image and texts in single Multipart request with Android Volley.
I had problem to upload file using Retrofit 2.0-SNAPSHOT before and found out the multipart format is not compatible with my server which accepts multipart/form-data. Here is my fix : https://github.com/jimxj/retrofit/commit/b44ab36ae8263622b8e8863d5b5e0985c56bc6b7
Still getting java.lang.IllegalStateException: JSON must start with an array or an object. from Gson when trying to post a multipart request where one of the parts is a file.
Retrofit 1.9.0 (using OkHttp 2.5.0):
@Multipart
@POST("/image/upload")
Observable<UploadImageResponse>
uploadImage(@Header(HEADER_AUTH_KEY) String token,
@Part("userId") String userId,
@Part("images") TypedFile file);
Where the file parameter is constructed as follows:
TypedFile file = new TypedFile("image/*", new File(path));
Retrofit 2.0.0-SNAPSHOT:
@Multipart
@POST("image/upload")
Observable<UploadImageResponse>
uploadImage(@Header(HEADER_AUTH_KEY) String token,
@Part("userId") String userId,
@Part("images") RequestBody file);
Where the file parameter is constructed as follows:
RequestBody file = RequestBody.create(MediaType.parse("image/*"), path);
Am I doing something incorrectly, or is this not the same thing that @JakeWharton said was fixed in master? Did you get it to work, @VadimWelldone?
I did notice Gson can serialize TypedFile to JSON, but trying the same thing on RequestBody returns null. Related? I might be barking up the wrong tree here.
A fixed was recently merged https://github.com/square/retrofit/issues/1092#event-416586627. Is it already in the snapshot?
snapshots are automatically deployed
On Thu, Sep 24, 2015 at 10:27 PM Tevin Jeffrey [email protected]
wrote:
A fixed was recently merged #1092 (comment)
https://github.com/square/retrofit/issues/1092#event-416586627. Is it
already in the snapshot?—
Reply to this email directly or view it on GitHub
https://github.com/square/retrofit/issues/1063#issuecomment-143106308.
@wKovacs64 It's very sad but I didn't manage to get it to work. I have rolled back to Retrofit 1.9.0 and continued to use it. Time frames was crucial for me and I chose working solution.
Possibly related @VadimWelldone issue
I'm using 2.0.0-beta2.
and using the converter GsonConverterFactory
It seem it was serializing the file as a Form Field instead of a File Field
Debugging from a Python(Flask) server showed that
print request.form
print request.files
ImmutableMultiDict([('file-field', u'/PATH/TO/FILE/FILE-NAME.jpg'), ('field', u'"value"')])
ImmutableMultiDict([])
rather than
ImmutableMultiDict([('field', value')])
ImmutableMultiDict([('file-field', <FileStorage: u'FILE-NAME.jpg' ('image/jpeg')>)])
2.0.0-beta2 got me past the JSON problem (not sure why the snapshot didn't help). Now investigating the lack of filename key in the Content-Disposition header field, as mentioned in https://github.com/square/retrofit/pull/1096#issuecomment-143526941 and the second half of #1130.
Do you have the headers from that request, @waleoyediran? I'm assuming yours must've included the filename somehow if you're seeing it on the web server like that.
I just tested with the method commented in #1140 and confirm that it works correctly. I am able to upload file in Multipart Request successfully. Sample code is below
public interface ApiInterface {
@Multipart
@POST ("/api/Accounts/editaccount")
Call<User> editUser (@Header("Authorization") String authorization, @Part("file\"; filename=\"pp.png\" ") RequestBody file , @Part("FirstName") RequestBody fname, @Part("Id") RequestBody id);
}
"file\" within @Part annotation is the name of the file parameter and "filename" is the name of the file that's going to be uploaded.
I executed the above request like this...
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));
Call<User> call = client.editUser(AZUtils.getToken(this), fbody, name, id);
call.enqueue(new Callback<User>() {
@Override
public void onResponse(retrofit.Response<User> response, Retrofit retrofit) {
AZUtils.printObject(response.body());
}
@Override
public void onFailure(Throwable t) {
t.printStackTrace();
}
});
Hope it helps.
@ayon115 Thank you so much. It really helped.
@ayon115 Thanks, it works! But how to specify a dynamic filename in the interface (or in the RequestBody)?
@mengoni , I think we can't specify dynamic filename in the interface right now. As far I know, it's probably okhttp matter. I am using @PartMap to avoid hard-coding filename with Interface method. You can see the following example that might be useful.
@Multipart
@POST ("/api/Events/editevent")
Call<Event> editEvent (@PartMap Map<String, RequestBody> params);
I call it by following way.
Map<String, RequestBody> map = new HashMap<>();
map.put("Id", AZUtils.toRequestBody(eventId));
map.put("Name", AZUtils.toRequestBody(titleView.getValue()));
if (imageUri != null) {
File file = new File(imageUri.getPath());
RequestBody fileBody = RequestBody.create(MediaType.parse("image/png"), file);
map.put("file\"; filename=\"pp.png\"", fileBody);
}
Call<Event> call = api.editEvent(map);
call.enqueue(new Callback<Event>() { }
The method toRequestBody just converts String into RequestBody
public static RequestBody toRequestBody (String value) {
RequestBody body = RequestBody.create(MediaType.parse("text/plain"), value);
return body ;
}
@ayon115 saved me as well. After upgrading from 1.9, in which I effortlessly uploaded image files with a @Multipart endpoint and a TypedFile attribute, the only thing I could do in Retrofit 2.0 was this ugly guy:
@Part("image\"; filename=\"image.jpg\" ") RequestBody image,
It works. This, unfortunately, does _not_ work, as the back end can not find a FILE param named 'image':
@Part("image") RequestBody image,
@mhousser The way forward is being discussed/tracked in #1140. I have a PR in to essentially bring back a version of the old TypedFile API, if that interests you. The end result would look something like this:
File file = /* ... */;
TypedFile image = new TypedFile("image/png", file);
// ...
@PartFile("image") TypedFile image
...which should look familiar.
Thanks!
@Part("image\"; filename=\"image.jpg\" ") RequestBody image
Is pretty hideous, but it works for now. I can hard-code the filename because I don't actually pay attention to it or use it server-side. (I hope this doesn't cause conflicts between different users uploading with the same filename..?)
Is anybody know how i can show progress when i'm uploading a file?
@ayon115
Thanks for you reply. I think there is a redundant comma in @Part.
It should looks like below:
public interface ApiInterface {
@Multipart
@POST ("/api/Accounts/editaccount")
Call<User> editUser (@Header("Authorization") String authorization, @Part("file\"; filename=\"pp.png ") RequestBody file , @Part("FirstName") RequestBody fname, @Part("Id") RequestBody id);
}
@abcdeiko extend RequestBody to receive an instance of a callback/listener/progress in the constructor. In the writeTo(BufferedSink sink) method call the listener as the bytes are read and written to the sink.
//The constructor
public ProgressRequestBody(final File file, final ProgressListener listener) {
this.file = file;
this.listener = listener;
}
//The method to overide
@Override
public void writeTo(BufferedSink sink) throws IOException {
long fileLength = file.length();
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
FileInputStream in = new FileInputStream(file);
long total = 0;
try {
int read;
while ((read = in.read(buffer)) != -1) {
this.listener.onProgress(total, fileLength);
total += read;
sink.write(buffer, 0, read);
}
} finally {
in.close();
}
}
//A simple callback
public interface ProgressListener {
void onProgress(final long current, final long max);
}
@tevjef thank you for reply.
My mistake was that i used old version (beta 1 instead beta 2).
Can anybody show me working solution?
Check #1217, for me, I have to put the image binary into request body of POST request, the following code is my woking solution:
@POST("trip/{tripId}/media/photos")
Call<MediaPost> postEventPhoto(
@Path("eventId") int tripId,
@Header("Authorization") String accessToken,
@Query("direction") String direction,
@Body RequestBody photo);
InputStream in = new FileInputStream(new File(media.getPath()));
byte[] buf;
buf = new byte[in.available()];
while (in.read(buf) != -1);
RequestBody requestBody = RequestBody
.create(MediaType.parse("application/octet-stream"), buf);
Call<MediaPost> mediaPostCall = tripApiService.postTripPhoto(
tripId,
((GlobalInfo) getApplicationContext()).getApiAccessToken(),
direction,
requestBody);
Thanks, but it does not work in my case
@timaxapa , please explain your problem in more details. Then we might be able to help. I am using the solution I described above in my 5 projects, all are working nicely. So, as a checklist I can suggest the following.
Try to post your request with file upload with Postman or any Rest client and Know the following from that if your request and upload is successful.
image/* or application/octet-stream or anything else.Hopefully you'll get your solution by checking these things. Good luck.
@timaxapa
First of all check what version you are using now (it is shoulde equal or above retrofit 2.0 beta 2, if you are using beta 1 it didn't work).
In your gradle file:
compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'
Create API service like this:
@Multipart
@POST("/upload")
// upload is a post field
// without filename it didn't work! I use a constant name because server doesn't save file on original name
Call<JsonObject> uploadImage(@Part("upload\"; filename=\"1\" ") RequestBody file);
And call it in your method like this:
public void upload(String path) { // path to file like /mnt/sdcard/myfile.txt
File file = new File(path);
// please check you mime type, i'm uploading only images
RequestBody requestBody = RequestBody.create(MediaType.parse("image/*"), file);
Call<JsonObject> call = service.uploadImage(requestBody);
call.enqueue(new Callback<JsonObject>() {
@Override
public void onResponse(Response<JsonObject> response, Retrofit retrofit) {
// on request finish
}
@Override
public void onFailure(Throwable t) {
// on request error
}
});
}
@abcdeiko Thank you very much for this detailed answer!
Hi everyone,
I have a problem with sending zipped file using Retrofit 2.0.0 betav2 (with Retrofit 1.9 everything was fine )
I've make changes, like You guys said in the posts above... and it works partly. The issue is quite strange - file is hitting the server. Server has the file. But Retrofit gives me a failure response. And I can't find the cause.
POST request:
@Multipart
@POST("get_lublin.php")
Call<Message> upload(@Part("file\"; filename=\"lublin112Message ") RequestBody zippedPackage);
Creating zippedFile:
RequestBody zippedPackage = RequestBody.create(MediaType.parse("multipart/form-data"),
new File(Environment.getExternalStorageDirectory().toString()
+ File.separator + ZIPFILENAME));
sendMessage(zippedPackage);
Using Retrofit service:
private void sendMessage(RequestBody zippedPackage) {
Call<Message> responseCall = RestClient.getInstance().getMessageService().upload(zippedPackage);
responseCall.enqueue(new Callback<Message>() {
@Override
public void onResponse(Response<Message> response, Retrofit retrofit) {
showMessageSentSuccessNotification();
}
@Override
public void onFailure(Throwable t) {
showMessageSentErrorNotifiaction();
}
});
}
I would be happy, if You could help me with this issue :) I don't wan't to back to older version, when almost everything is working elegantly :)
@bartoszbanczerowski please take server answer as plain text. Are you sure what you POJO model has equal fields with server answer?
Retrofit call onFailure method?
@abcdeiko - yes, Retrofit gives me on call onFailure method, and this is propably caused by Call
Edit:
And this was a root of all evil which I have :D Server was sending only a string response:
"Upload complete!Your message has been sent.woot!" :) I was so certain, that server should send a POJO, what I didn't even reconsider another possibility - it's one of this funny stories, when You read documentation how the response should look like, and reality corrects Your expectations :)
Now I'm using ResponseBody from OkHttp, and everything is fine, I can go back to my private life and see the sun tomorrow :)
Maybe this will help anyone, in close or further future. Below is actual code:
POST request:
@Multipart
@POST("get_lublin.php")
Call<ResponseBody> upload(@Part("file\"; filename=\"lublin112Message ") RequestBody zippedPackage);
Creating zippedFile:
RequestBody zippedPackage = RequestBody.create(MediaType.parse("multipart/form-data"),
new File(Environment.getExternalStorageDirectory().toString()
+ File.separator + ZIPFILENAME));
sendMessage(zippedPackage);
Using Retrofit service:
private void sendMessage(ResponseBody zippedPackage) {
Call<ResponseBody> responseCall = RestClient.getInstance().getMessageService().upload(zippedPackage);
responseCall.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Response<ResponseBody> response, Retrofit retrofit) {
showMessageSentSuccessNotification();
}
@Override
public void onFailure(Throwable t) {
showMessageSentErrorNotifiaction();
}
});
}
Thanks @abcdeiko for such fast response :)
@abcdeiko Thank you. After many hours it worked for me ; )
Here I put some important details:
ApiService.java
@Multipart
@Headers({ACCEPT_APPLICATION_JSON, ENTERPRISE_CODE})
@POST("/API_PATH/{upload_id}/upload_file")
Call<UploadResponse> uploadFile(@Header(LOGIN) String login, @Header(TOKEN) String token, @Path("upload_id") int uploadId, @Part("file\"; filename=\"picture.jpg\" ") RequestBody file);
Content-Type: multipart/form in your @Headers annotationApi.java
MediaType mediaType = MediaType.parse("image/jpg");
RequestBody requestBody = RequestBody.create(mediaType, file);
Call<UploadResponse> uploadFile = service.uploadFile(login, token, uploadId, requestBody);
@Part annotation@ayon115 Thank you very much.
@fernandodev Here what are the values of {ACCEPT_APPLICATION_JSON, ENTERPRISE_CODE}
@ramesh586 sry, I've just copied and pasted here my snippet code. They are default Headers for my api.
Helpful discussion. Let me write my code too, which i have managed to upload multiple images with specific names using Retrofit2:
@Multipart
@POST(ConstantsWebService.UPLOAD_SERVICES_IMAGE)
Call<List<String>> uploadImage(@Header("Authorization") String token,
@Header("Handshake") String handshake,
//@Part("file\"; filename=\"902367000083-1.jpg") RequestBody mapFileAndName); //for sending only one image
@PartMap() Map<String,RequestBody> mapFileAndName); //for sending multiple images
...
HashMap<String,RequestBody> map=new HashMap<>(listOfNames.size());
RequestBody file=null;
File f=null;
for(int i=0,size=listOfNames.size(); i<size;i++){
try {
f = new File(context.getCacheDir(), listOfNames.get(i)+".jpg");
FileOutputStream fos = new FileOutputStream(f);
Bitmap bitmap = getImageFromDatabase(listOfNames.get(i));
if(bitmap!=null){
bitmap.compress(Bitmap.CompressFormat.JPEG, 0 /*ignored for PNG*/, fos);
fos.flush();
fos.close();
}else{
view.showErrorView("imageNotFound"); //todo
return;
}
} catch (Exception e) {
e.printStackTrace();
view.showErrorView("imageNotFound || file not created"); //todo
return;
}
file=RequestBody.create(MediaType.parse("multipart/form-data"), f);
map.put("file\"; filename=\""+listOfNames.get(i)+".jpg",file);
file=null;
f = null;
}
serviceOperation.uploadImage(token, handshake,map).enqueue(){..}
@ayon115 thank you, your solution worked like charm.....
...@Part("file\"; filename=\"picture.jpg\" ") RequestBody file...
@jemshit How to receive it on server. when I use
map.put("file\"; filename=\""+listOfNames.get(i)+".jpg",file);
map.put("file\"; filename=\""+listOfNames.get(i)+".jpg",file);
file overwrite previous value because key is same. If I change key like file1, file2 and used $_FILES['file'] it get null at server side. How to pass variable name which can be used in $_FILES array.
No idea about server side
On Sat, Jan 2, 2016, 13:27 Joginder Sharma [email protected] wrote:
@jemshit https://github.com/jemshit How to receive it on server. when I
use map.put("file\"; filename=\""+listOfNames.get(i)+".jpg",file);file overwrite preveoius value. If I change key and used $_FILES['file']
it get null at server side. How to pass variable name which can be used in
$_FILES array.—
Reply to this email directly or view it on GitHub
https://github.com/square/retrofit/issues/1063#issuecomment-168381652.
@jemshit
I receive it at server side using
map.put("file[i]\"; filename=\""+listOfNames.get(i)+".jpg",file);
@ayon115
Actually I am trying to use dynamic file name using @PartMap
@PartMap Map<String, RequestBody> params
When I post the image on server by using dynamic file name (as per your suggestion), it gives me
JSON must start with an array or an object error.
If I remove the logic for dynamic file name and go for static, then everything works fine.
Any idea how to fix this?
@pmk2429 please share your code snippet. Thanks
@pmk2429 You are sending data in a wrong format to server. For me also it take 2 hrs. to get work @PartMap at server side. If you are using PHP then you can use json_encode ($_REQUEST) to know what is your server receiving.
Building the RequestBody
File file = new File(selectedImagePath);
image_name = file.getName();
RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file);
My API Service method:
@Multipart
@POST("observations/upload_tick_pic")
Call<Observation> upload(@PartMap Map<String, RequestBody> params);
This is where I make a call to API service method.
Map<String, RequestBody> requestBodyMap = new HashMap<>();
RequestBody id = RequestBody.create(MediaType.parse("text/plain"), observation_id);
requestBodyMap.put("id", id);
String fileName = "file\"; filename=\"" + IMAGE_NAME;
requestBodyMap.put(fileName, mRequestBody);
imageUploadCall = mApiService.upload(requestBodyMap);
@joginder89
Any idea how to decode the request in Node.js?
@pmk2429 I think it has nothing to do with your file upload. Check your "Observation" class and the Response that you get from API. I think your POJO class (Observation) has some mapping issue with the Response that you get.
@ayon115
It seems to work fine with the static file name option. Once I upload the pic, the server responses back the entire Observation.
This seems to work fine with @Part rather than @PartMap.
@jemshit
if i use your code to send multiple images it only send the first images, no matter how many I add.
which retrofit version did you use?
2.0.0-beta2
On Thu, Jan 14, 2016, 15:33 psyopussy [email protected] wrote:
@jemshit https://github.com/jemshit
if i use your code to send multiple images it only send the first images,
no matter how many I add.which retrofit version did you use?
—
Reply to this email directly or view it on GitHub
https://github.com/square/retrofit/issues/1063#issuecomment-171645793.
@jemshit
i am sorry to have bothered you, it works.
my interceptor just showed one upload but the backend actually got both! :)
I am trying to upload image by POST multipart request which should look like this :
-----------------------------219391268715340
Content-Disposition: form-data; name="photos[]"; filename="DSCF0157-Laptop.JPG"
Content-Type: image/jpeg
(byte-data)
My code :
MediaType mediaType = MediaType.parse("image/jpeg");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte[] byteArray = stream.toByteArray();
RequestBody file=RequestBody.create(mediaType, byteArray);
map.put("form-data; name=\"photos[]\"; filename=\""+filename+".jpg",file);
I use map because of @PartMap annotation - I want to upload multiple files. Is my code correct ?
Please use StackOverflow and the 'retrofit' tag for usage questions. GitHub
issues are far too primitive and useless of a platform for proper support.
On Tue, Jan 19, 2016 at 5:53 PM dzakens [email protected] wrote:
I am trying to upload image by POST multipart request which should look
like this :-----------------------------219391268715340
Content-Disposition: form-data; name="photos[]";
filename="DSCF0157-Laptop.JPG"
Content-Type: image/jpeg(byte-data)
My code :
MediaType mediaType = MediaType.parse("image/jpeg"); ByteArrayOutputStream stream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream); byte[] byteArray = stream.toByteArray(); RequestBody file=RequestBody.create(mediaType, byteArray); map.put("form-data; name=\"photos[]\"; filename=\""+filename+".jpg",file);I use map because of @PartMap annotation - I want to upload multiple
files. Is my code correct ?—
Reply to this email directly or view it on GitHub
https://github.com/square/retrofit/issues/1063#issuecomment-173014240.
for my project this is my snippet. it work :
Interface
@Multipart
@POST("Api/Mobile")
Call<OutputReturn> uploadAsset(@PartMap() Map<String, RequestBody> mapPhoto);
Retrofit2
HashMap<String, RequestBody> map = new HashMap<>();
File file = new File(photoFilename);
String filename = file.getName();
RequestBody photo = RequestBody.create(MediaType.parse("multipart/form-data"), file);
map.put("file\"; filename=\"" + filename, photo);
Gson gson = new Gson();
String strJson = gson.toJson(objectClass);
RequestBody json = RequestBody.create(MediaType.parse("text/plain"), strJson);
map.put("json", json);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://myserver.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
WebServiceApi webServiceApi = retrofit.create(WebServiceApi.class);
Call<OutputReturn> call = webServiceApi.uploadAsset(map);
Response<OutputReturn> response = call.execute();
Web API (ASP .Net Web API)
public class MobileController : ApiController
{
[System.Web.Http.HttpPost]
public object postData()
{
var httpRequest = HttpContext.Current.Request;
var json = httpRequest.Form.Get("json").ToString();
var files = httpRequest.Files;
}
}
I am using Retrofit 2.0 to upload an image using Multipart.The code is given below : 1.build.gradle
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.squareup.retrofit2:retrofit:2.0.0-beta3'
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta3'
compile 'com.squareup.picasso:picasso:2.5.2'
}
2.ServiceGenerator.java
`public class ServiceGenerator {
public static final String API_BASE_URL = "http://phpstack-11819-25991-62288.cloudwaysapps.com/";
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
public static <S> S createService(Class<S> serviceClass) {
Retrofit retrofit = builder.client(httpClient.build()).build();
return retrofit.create(serviceClass);
}
}`
3.WelcomeActivity.java
`APIServiceInterface service =
ServiceGenerator.createService(APIServiceInterface.class);
String descriptionString = "hello, this is description speaking";
RequestBody description =
RequestBody.create(MediaType.parse("multipart/form-data"), descriptionString);
File file = new File(path);
RequestBody requestBody =
RequestBody.create(MediaType.parse("multipart/form-data"), file);
String type = "photo";
int active = 1;
Call<ResponseUploadImage> call = service.uploadImage(userID, type, active, accessToken, requestBody, description);
call.enqueue(new Callback<ResponseUploadImage>() {
@Override
public void onResponse(Response<ResponseUploadImage> response) {
Log.e("Status Code", String.valueOf(response.code()));
if (response.code() == 200) {
ResponseUploadImage responseUploadImage = response.body();
String statusCode = responseUploadImage.getStatusCode();
Log.e("StatusCode", statusCode);
Detail detail = responseUploadImage.getDetail();
UploadData uploadData = detail.getUploadData();
String fileName = uploadData.getFileName();
Log.e("FileName",fileName);
}
}
@Override
public void onFailure(Throwable t) {
Log.e("Response", "failure");
Log.e("StackTrace", String.valueOf(t));
}`
While parsing the JSON response ,i am getting the status code of 200 which is specified in the Response String.But i am not able to receive file_name from the upload_data object .I am not able to find where i am doing the mistake.Please help me to fix the problem .
URL To be used is :
http://phpstack-11819-25991-62288.cloudwaysapps.com/webservice/media/?user_id=<user_id>&type=photo&active=1&access_token=<access_token>
Hey @ayon115 and guys.
I've added a new section on wiki: How to upload file using retrofit 2
If you have more solutions, please, don't forget to keep wiki updated. I've put two examples that I've tried but if you have one more, share with us! ;)
thanks guys,
i resolved my problem at Retrofit 2.0.0beta-2 with this
@Multipart
@POST(URLCons.URL_UPLOAD_PHOTO_PROFILE)
Call<ApiResponse> uploadPhotoProfile(
@Part("photo\"; filename=\"picture.jpg\" ") RequestBody requestBody,
//alway send
@Part("id_user") RequestBody id_user,
@Part("sess_mobile") RequestBody sess_mobile);
i have tried all the solutions mentioned in this forum and am still not able to post a multipart file.
I am using beta3 version of retrofit.
At the backend, i am able to receive the request, but the multipart parameter is empty.
Can someone please suggest either another approach or a work-around?
@abhishekgargg i think the best way to ask a question is using stackoverflow project.
Anyway, if you want to see any answers you should post some of your code.
If all the answer above are not worked. Try using @Body and compose RequestBody yourself.
Here is my approach:
@POST("me")
Call<RestaurantPhoto> update(@Body RequestBody body);
public Me update(String name, File photo) throws IOException, ApiException {
RequestBody body = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("name", name)
.addFormDataPart("photo", photo.getName(),
RequestBody.create(MediaType.parse("image/jpeg"), photo))
.build();
Response<Me> response = usersApi.update(body).execute();
if(response.isSuccess()) {
return response.body();
} else {
throw new ApiException(response);
}
}
https://github.com/square/retrofit/issues/1063#issuecomment-188934990 worked for me.
All others approach don't :(
See my answer
http://stackoverflow.com/a/35790366/776388
Hello,
If instead of uploading an image on a server, I would have to upload an audio file ".mp4".
What would be the differences ?
When I will use Mediatype.parse what should be th string parameter of it ?
Thanks
Back to old conversation, i have a web service which works with this request, which has only @Body contains text and images:
@POST(Constants.INSERT_POST)
public void InsertPost(@Body MultipartTypedOutput attachments, CoreCallBack<PrimitiveResponse> OnResponse
And request is made here:
MultipartTypedOutput multipartTypedOutput = new MultipartTypedOutput();
multipartTypedOutput.addPart("Body", new TypedString(postBody));
multipartTypedOutput.addPart("Token", new TypedString(getToken()));
multipartTypedOutput.addPart("CategoryId", new TypedString(categoryId));
if (postPictures != null) {
for (File file : postPictures) {
multipartTypedOutput.addPart("photo" + postPictures.indexOf(file), new TypedFile("image/jpg", file));
}
}
restClientApplication.getApiResponse().InsertPost(multipartTypedOutput, callBack);
After i move to Retrofit 2, this didn't work, i think it is because of MultipartTypedOutput. Then i changed above to this:
@Multipart
@POST("api/Post/Insert")
Call<PrimitiveResponse> InsertPost(@PartMap() Map<String,RequestBody> mapFileAndName,
@Part("Token") String Token,
@Part("CategoryId") String CategoryId,
@Part("Body") String Body);
which didn't work. Then i changed all Strings to RequestBody, now it works. Request is like below:
HashMap<String, RequestBody> map=new HashMap<>(fileList.size());
RequestBody file=null;
for(int i=0,size=fileList.size(); i<size;i++) {
file = RequestBody.create(MediaType.parse("image/jpg"), fileList.get(i));
map.put("file\"; filename=\"" + "photoname" + i + ".jpg", file);
}
postService.InsertPost(map,
RequestBody.create(MediaType.parse("text/plain"), realmManager.getToken()),
RequestBody.create(MediaType.parse("text/plain"), categoryId),
RequestBody.create(MediaType.parse("text/plain"), body));
I also had to change name along with filename, so this line is changed:
map.put("name"+i+"\"; filename=\"" + "photoname" + i +".jpg", file); // name, filename, file
If you have trouble with MultipartTypedOutput, name, filename on Retrofit2, you might want to check this.
I had the same issue on Retrofit version 2.0.0-beta3 and
Only @ayon115 RequestMap solution works, i couldn't get it work none of those others...
@JakeWharton @ayon115
Can someone help me with an example of using PartMap. Our rest method consumes one json object and an array of files using a multipart upload. Here is the method signature:
@RequestMapping(method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ResponseStatus(HttpStatus.ACCEPTED)
public ResponseEntity
@RequestPart("request")
final JobRequest jobRequest,
@RequestPart("attachment")
final MultipartFile[] attachments,
@RequestHeader(value = FORWARDED_FOR_HEADER, required = false)
final String clientHost,
final HttpServletRequest httpServletRequest
)
I have been trying so many different variations and struggling with it.
Thanks.
I confirm @jemshit solution is the only one that worked for me, thanks!
Why retrofit developers cannot just create nice and smooth HOWTO? Make some code samples... Why everyone has to be a damn investigator to make everything works? Can't they just understand that if we are here, then the problem still exists? Have to wait for weeks to get any response on Stackoverflow.
Btw, I have "BAD REQUEST' with @jemshit method.
Map<String, RequestBody> requestDataMap = new HashMap<>();
RequestBody userName = RequestBody.create(MediaType.parse("text/plain"), name.getText().toString());
RequestBody userSecondName = RequestBody.create(MediaType.parse("text/plain"), lastName.getText().toString());
RequestBody userEmail = RequestBody.create(MediaType.parse("text/plain"), email.getText().toString());
RequestBody userPassword = RequestBody.create(MediaType.parse("text/plain"), PasswordUtils.encodePassword(encodePassword()));
RequestBody userGender = RequestBody.create(MediaType.parse("text/plain"), male.isChecked() ? EmailProfile.GENDER_MALE : EmailProfile.GENDER_FEMALE);
RequestBody avatar = RequestBody.create(MediaType.parse("image/jpg"), avatarPath);
Map<String, String> params = new ParkApiUrl.Builder(getActivity()).buildParams();
RequestBody height = RequestBody.create(MediaType.parse("text/plain"), params.get(ParkApiUrl.PARAM_HEIGHT));
RequestBody width = RequestBody.create(MediaType.parse("text/plain"), params.get(ParkApiUrl.PARAM_WIDTH));
RequestBody target = RequestBody.create(MediaType.parse("text/plain"), params.get(ParkApiUrl.PARAM_TARGET));
requestDataMap.put(ParkApiUrl.PARAM_USER_NAME, userName);
requestDataMap.put(ParkApiUrl.PARAM_USER_SECOND_NAME, userSecondName);
requestDataMap.put(ParkApiUrl.PARAM_EMAIL, userEmail);
requestDataMap.put(ParkApiUrl.PARAM_USER_ENCODED_PASSWORD, userPassword);
requestDataMap.put(ParkApiUrl.PARAM_USER_GENDER, userGender);
requestDataMap.put("form-data; name=\"photo\"; filename=\"image.jpg\"", avatar);
This is Retrofit suff:
@Multipart
@POST("/api/v2/user/email_register?_height=1184&_target=android/2&_width=768")
Observable<UpdateUserInfoPayload> register(
@Header("x-device-id") String deviceId,
@PartMap() Map<String, RequestBody> map
);
@lectricas Have you look at https://github.com/square/okhttp/wiki/Recipes?
Yes, @kafji, I've seen this guide. It is for OKHTTP , not for retrofit. I've already implemented my request using okhttp only but it's not enough. I need to make it with retfit. Nice EXAMPLE android project with all the features implemented would be more that enought for all who struggles.
My solution for this problem:
@Multipart
@POST("/api/.../{id}/audio")
Call<MyResponse> sendAudio(
@Path("id") String id,
@Part MultipartBody.Part part
);
Called like this:
RequestBody requestBody = RequestBody.create(MEDIA_TYPE_AUDIO, audioFile);
MultipartBody.Part part = MultipartBody.Part.createFormData("message_audio[audio]", audioFile.getName(), requestBody);
service.sendAudio(id, part)...
What worked for me is as follows:
@Multipart
@POST("users/{id}/avatar")
Observable<Void> uploadAvatar(@Header("Authorization") String token, @Path("id") String userId, @Part("source\"; filename=\"image.jpg") RequestBody image);
Note that the difference from a few other answers here is filename=\"image.jpg" without the escape char at the end.
MultipartBody.Builder builder = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(ParkApiUrl.PARAM_USER_NAME, name)
.addFormDataPart(ParkApiUrl.PARAM_USER_SECOND_NAME, last)
.addFormDataPart(ParkApiUrl.PARAM_EMAIL, email)
.addFormDataPart(ParkApiUrl.PARAM_USER_ENCODED_PASSWORD,
PasswordUtils.encodePassword(pwd))
.addFormDataPart(ParkApiUrl.PARAM_USER_GENDER, sex)
.addFormDataPart(ParkApiUrl.PARAM_PARSE_ID,
ParseInstallation.getCurrentInstallation().getObjectId());
if (!TextUtils.isEmpty(avatarPath)) {
Log.d("RegistrationFragment", avatarPath);
File file = new File(avatarPath);
int size = (int) file.length();
byte[] bytes = new byte[size];
try {
BufferedInputStream buf = new BufferedInputStream(new FileInputStream(file));
buf.read(bytes, 0, bytes.length);
buf.close();
} catch (IOException e) {
e.printStackTrace();
}
builder.addPart(Headers.of("Content-Disposition", "form-data; name=\"photo\"; filename=\"image.jpg\""), RequestBody.create(MEDIA_TYPE_JPG, bytes));
}
work like a charm!
This is my code. This works...
public interface FileUploadService {
@Multipart
@POST("upload")
Call<ResponseBody> upload(@PartMap Map<String, RequestBody> params);
}
private void uploadFile() {
FileUploadService service =
ServiceGenerator.createService(FileUploadService.class);
File file = new File(selectedImagePath);
image_name = file.getName();
String fileName = "file\"; filename=\"" + image_name;
RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file);
RequestBody id = RequestBody.create(MediaType.parse("multipart/form-data"), observation_id);
Map<String, RequestBody> requestBodyMap = new HashMap<>();
requestBodyMap.put("id", id);
requestBodyMap.put(fileName, requestBody);
Call<ResponseBody> call = service.upload(requestBodyMap);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call,
Response<ResponseBody> response) {
Log.v("Upload", "success");
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.e("Upload error:", t.getMessage());
}
});
}
This is my code and it's working flawlessly
Service
@Multipart
@POST("File/upload")
Observable<UploadImageApiResult> uploadImage(
@Part("token") RequestBody token,
@Part("player_id") RequestBody playerId,
@Part MultipartBody.Part image
);
Call
restClient.getImageService().uploadImage(
RequestBody.create(MediaType.parse("text/plain"), getApiToken()),
RequestBody.create(MediaType.parse("text/plain"), form.getPlayerId()),
MultipartBody.Part.createFormData(
"file",
form.getFile().getName(),
RequestBody.create(MediaType.parse("image/*"), form.getFile())
)
)
@Tar-SSA How are you able to use @Part without passing a value to it like so @Part("blah") ?? that annotation gives a compile time error if one uses it like you have
@bhargavms
This is my dependencies related to Retrofit
compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
compile 'com.squareup.okhttp3:okhttp-urlconnection:3.2.0'
compile 'com.squareup.okhttp3:okhttp:3.2.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.2.0'
Are they the same with yours?
@Tar-SSA ah thank you I was still using the 2.0.0-beta version and hence the issue
I was never work with Jsoup before, and now I have a project, where guys were using JSoup lib, and I need to do some refactoring and make same work but with retrofit2...
I stuck with converting request that send image file. Here is original JSoup request:
Connection.Response result = Jsoup.connect(apiURL + "sendImg/")
.method(Connection.Method.POST)
.header("Token", XCSRFToken)
.data("source", currentImage.getMD5().concat(".jpg"),
new FileInputStream(bitmapURI.getPath()))
.execute();
here is what i try to do with retrofit:
``````
``````
@Multipart
@POST("sendImg/")
Call<CbSendImage> sendImage(@Header("Token") String token, @Part MultipartBody.Part file);
public void sendImage(File file) {
RequestBody requestFile =
RequestBody.create(MediaType.parse("multipart/form-data"), file);
MultipartBody.Part body =
MultipartBody.Part.createFormData("source",
currentImage.getMD5().concat(".jpg"), requestFile);
mSendImageCall = mServerApi.sendImage(getToken(), body);
mSendImageCall.enqueue(sendImageCallback);
}
but request still failed...
Any ideas how convert that request correct? Thanks!
```
@Tar-SSA , @sbljayarathna , @lectricas , @markini , @jemshit , @CateyesLin , @DeepakRattan ??
Anyone? Please help to find solution!
This is not a help forum. Try StackOverflow.
@Multipart
@POST("/uploadFile")
Call
@Part("empsno") String empsno,
@Part("storesno") String storesno,
@Part("lrSno") String lrSno,
@Part("recQty") String recQty,
@Part("recVol") String recVol,
@Part("recWgt") String recWgt,
@Part("damageQty") String damageQty,
@Part("looseQty") String looseQty,
@Part("deliveryDate") String deliveryDate,
@Part("deliveryTime") String deliveryTime,
// @Part("uploadFile") RequestBody file,
// @Part("uploadFile";filename="audex.jpg" ") RequestBody part,
@Part("remarks") String remarks,
@Part("receivedBy") String receivedBy,
@Part("ipAddress") String ipAddress,
@Part MultipartBody.Part images
);
private void uploadFile(Uri fileUri) {
File file = new File(fileUri.getPath());
if (file.exists()) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
Log.e(TAG, "uploadFile:File " + file);
MediaType MEDIA_TYPE_PNG = MediaType.parse("multipart/form-data");
AudexInterface service = retrofit.create(AudexInterface.class);
RequestBody requestFile = RequestBody.create(MEDIA_TYPE_PNG, file);
MultipartBody.Part filePart = MultipartBody.Part.createFormData("uploadFile", file.getName(),
RequestBody.create(MediaType.parse("image/*"), file));
Log.e(TAG, "uploadUri: " + strEmpsno + " " + strStoreSno + " " + strLrno + " " + strRecqty + " " + strDeliverydate + " " + strDeliverytime);
Call<PODResponse> call = service.postFile(strEmpsno,
strStoreSno,
strLrno,
strRecqty,
strRecvol,
strRecwgt,
strDamageqty,
strLooseqty,
strDeliverydate,
strDeliverytime,
// requestFile,
strRemarks,
strReceivedby,
strIpaddress,
filePart);
call.enqueue(new Callback<PODResponse>() {
@Override
public void onResponse(Call<PODResponse> call, Response<PODResponse> response) {
Log.e(TAG, "onResponse:uploadUri " + response.isSuccessful());
if (response.isSuccessful()) {
Log.e(TAG, "uploadUri: " + response.body().getResult());
}
}
@Override
public void onFailure(Call<PODResponse> call, Throwable t) {
Log.e(TAG, "onFailure:uploadUri " + t.getLocalizedMessage());
}
});
}
}
I also tried this way but not getting success. Server is asking for "insert your image". please help me
If i look your code
from
MultipartBody.Part filePart = MultipartBody.Part.createFormData("uploadFile", file.getName(),
RequestBody.create(MediaType.parse("image/*"), file));
use
MultipartBody.Part filePart = MultipartBody.Part.createFormData("filePart", file.getName(),
RequestBody.create(MediaType.parse("image/*"), file));
and
call for file with name
filePart
I hope work
@ayon115 it solve my problem thank you very much, before i user @Part("username") String username ,there are a exception JSON must start with an array or an object. but when i use your solution,just change String to RequestBoby,it help me .thank you
Glad to know it helped you :) @jounghu
@ayon115 , I am having problem uploading a video to server using Retrofit2 multipart. Please could you help? I have posted a question in stackverflow. https://stackoverflow.com/questions/44319052/upload-video-using-retrofit2
Thank you, everyone, for your solutions, it helped me a lot and resolved my issues, this issue thread is a great guide for other developers facing similar issues.
I need to upload file inside a JSON object like below.
[
{
"imageType": "image_type",
"image": "imageObj", //Image File Here
"imageName": "abc1"
},
{
"imageType": "image_type",
"image": "imageObj", //Image File Here
"imageName": "abc2"
}
]
How to achieve this via retrofit 2.0.
How to upload image and content in the same time with retrofit use Oauth 1.0
Hello any one can help me to upload audio file using retrofit i am not able to upload audio file and play it
Thanks
On Thu, Jan 25, 2018 at 1:31 PM, nicemak notifications@github.com wrote:
I am having problem uploading an image to server using Retrofit2
multipart. Please could you help? I have posted a question in stackverflow.
https://stackoverflow.com/questions/48436618/unable-to-
upload-image-with-retrofit-2—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/square/retrofit/issues/1063#issuecomment-360389519,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AKq7H_hLPcrTthuXbdSJ79VDvKK4CRGeks5tODTCgaJpZM4F450F
.
@markini thank u
来自中国的娃娃们,看这里。
@Multipart
@POST("/api/.../{id}/audio")
Call
@Path("id") String id,
@Part MultipartBody.Part part
);
RequestBody requestBody = RequestBody.create(MEDIA_TYPE_AUDIO, audioFile);
MultipartBody.Part part = MultipartBody.Part.createFormData("message_audio[audio]", audioFile.getName(), requestBody);
service.sendAudio(id, part)...
@markini 这位大佬的方案亲测有效。
Just in case anyone struggles with uploading an image via ImageField in Django,
change ImageField to FileField.
Doesn't work with ImageField.
@rajvijay68 I belive ImageField will work if creating the RequestBody directly from the file, instead of using multipart form data. Anyways, just leaving this here for someone struggling too.
Most helpful comment
@mengoni , I think we can't specify dynamic filename in the interface right now. As far I know, it's probably okhttp matter. I am using @PartMap to avoid hard-coding filename with Interface method. You can see the following example that might be useful.
I call it by following way.
The method toRequestBody just converts String into RequestBody