AWS S3 Rest API with Android Retrofit V2 library, uploaded image is damaged

You are sending a multipart payload, but forcing the Content-type to be image/jpeg. Your jpg is corrupt because S3 probably saved the multipart headers into your jpg file since you told it the whole message was a JPG. Since you do not actually have multiple parts to send, you can drop the Multipart annotation and use Body instead of Part for your RequestBody

public interface AwsS3 {

    @PUT("/{Key}")
    Call<String> upload(@Path("Key") String Key,
                @Header("Content-Length") long length,
                @Header("Accept") String accept,
                @Header("Host") String host,
                @Header("Date") String date,
                @Header("Content-type") String contentType,
                @Header("Authorization") String authorization,
                @Body RequestBody body);
}

You should also be able to remove explicitly setting the Content-type and Content-length headers.


I have the same problem, and as I use Fiddler checked the HTTP request content, I found retrofit 2.0.0 beta1 has a different with 1.9.0.

In my problem, the different of HTTP request content prevent server get the correct data.

In order to make a same HTTP request content, i do next steps using retrofit 2.0.0 deta1.


In the retrofit service, add a form-data header for the http request;

@Headers("Content-Type: multipart/form-data;boundary=95416089-b2fd-4eab-9a14-166bb9c5788b")

int retrofit 2.0.0 deta1, the header using @Multipart will get a data like this:

Content-Type: multipart/mixed

as the deafult value is mixed, and has no boundary title.


Do not using @Multipart to upload file, just using @Body RequestBody

if you using @Multipart to request Server, you have to pass param(file) through

@Part(key), then a new problem you will get. May be retrofit 2.0.0beta1 has a BUG ..., @Multipart generate a bad http request compile with 1.9.0.


When you call the method, you need pass MultipartRequestBody to @Body RequestBody

Using MultipartBuilder to create a MultipartRequestBody, when you new MultipartBuilder, call this consturt:

new MultipartBuilder("95416089-b2fd-4eab-9a14-166bb9c5788b")

the param is you set int @headers(boundary=)

builder.addFormDataPart(String name, String filename, RequestBody value)

This method will help form a data like below int HTTP request content:

Content-Disposition: form-data; name="imgFile"; filename="IMG_20150911_113029.jpg" Content-Type: image/jpg Content-Length: 1179469

RequestBody value is what you has generate in your code.

I just resolve this problem temporary.

Hope can help you!


RequestBody avatarBody = RequestBody.create(MediaType.parse("image"),file);
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", file.getName(), avatarBody);


@Multipart
@POST(url)
Call<ResponseBody> uploadImageAmazon(
            @Part MultipartBody.Part filePart);

I had same experience, and solved it by https://github.com/square/retrofit/issues/2424 this solution


I have used Retrofit 2 resolve and I use Body instead of Part for your RequestBody in interface

@PUT("")
Call<String> nameAPI(@Url String url, @Body RequestBody body);

and java code

// Prepare image file
File file = new File(pathImg);
RequestBody requestBody = RequestBody.create(MediaType.parse("image/jpeg"), file);

Call<String> call = SingletonApiServiceS3.getInstance().getService().nameAPI(
        path,
       requestBody
);
call.enqueue(new Callback<String>() {
    @Override
    public void onResponse(Call<String> call, final Response<String> response) {

        if (response.isSuccessful()) {
            // Your handling
        } else {
            // Your handling
       }
   }

   @Override
   public void onFailure(Call<String> call, Throwable t) {
       Toast.makeText(getContext(), "onFailure : "+t.getMessage().toString(),Toast.LENGTH_SHORT).show();
   }
});