Related
I know it is not wise to use multipart for simple text authentication. but I need to use it with api provided to me.
I tried all the methods possible.
It's working fine with postman
but not with retrofit 2
request type details
request type details
code used
tried
//RequestBody requestNameRq = RequestBody.create(MediaType.parse("text/plain"),serviceNameValue);
//RequestBody requestAmountRq = RequestBody.create(MediaType.parse("text/plain"),serviceAmountValue.toString());
/* Create Request Body */
//MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM)
// .addFormDataPart("service",serviceNameValue)
// .addFormDataPart("amount", String.valueOf(serviceAmountValue));
//RequestBody requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM)
// .addFormDataPart("service",serviceNameValue)
// .addFormDataPart("amount",serviceAmountValue.toString()).build();
//MultipartBody.Part multipartRequestBody = MultipartBody.Part
// .createFormData("service",serviceNameValue)
// .createFormData("amount",serviceAmountValue.toString());
//MultipartBody multipartBody = builder.build();
Code for Apiservice
#POST("services")
Call<AddServiceResponse> addService(#Header("Authorization") String authToken,
//#Body MultipartBody body);
#Part("service") RequestBody service,
#Part("amount") RequestBody amount);
//#Part("service") String service,
//#Part("amount") String password);
//#Part("service") RequestBody service,
//#Part("amount") RequestBody amount);
}
Please try to add
#Multipart
before
#POST("services")
Modify your ApiService class
#Multipart
#POST("services")
Call<AddServiceResponse> addService(
#Header("Authorization") String authToken,
#Part("service") MultipartBody.Part service,
#Part("amount") MultipartBody.Part amount);
Then create MultipartBody
MultipartBody.Part serviceBody = MultipartBody.Part.createFormData("service", "Somethin2");
MultipartBody.Part amountBody = MultipartBody.Part.createFormData("amount", "2344");
Then call
apiService.addService(serviceBody, amountBody);
I have an ArrayList of custom objects, each with about 10 fields, that I already managed to upload to our server. The problem is that one of the fields is a String which contains a Base64-encoded string that I converted from a file, which the Retrofit Gson creater does not seem to like. This problem could be solved by just sending all the fields without the image, and then after that upload all the images using ftp, but it would be so much easier if I could just put the image in the object somehow.
Question: How can I send a Base64-encoded string as a field inside a custom object to a url using Retrofit?
#FormUrlEncoded
#POST("/UploadImages")
Call<ResponseBody> postImages(#Body ArrayListImage img);
//POJO CLASS
public class ArrayListImage {
#SerializedName("image")
#Expose
private ArrayList<String> image;
public ArrayListImage(ArrayList<String> image) {
this.image=image;
}
}
Below is the RequestBody code which i use to upload file using Retrofit:
RequestBody lRequestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file);
MultipartBody.Part lFile = MultipartBody.Part.createFormData("file", file.getName(), lRequestBody);
MultipartBody.Part title = MultipartBody.Part.createFormData("title", file.getName());
MultipartBody.Part lFilenamebase64 = MultipartBody.Part.createFormData("filenamebase64", base64EncodedFileName);
To encode file name:
String base64EncodedFileName = Base64.encodeToString(file.getName().getBytes(Charsets.UTF_8), Base64.URL_SAFE | Base64.NO_WRAP);
I defined the api like:
#Multipart
#POST("/upload")
Observable<Response<ResponseBody>> uploadFile(#Part MultipartBody.Part file, #Part MultipartBody.Part title, #Part MultipartBody.Part base64EncodedFileName);
I hope it might help you.
//Convert Object list into json string.
Gson gson = new Gson();
String objListString = gson.toJson(objectList);
#FormUrlEncoded
#POST("********")
Call<JsonObject> sendObjectList(#Field("objListString") String objListString);
And at the web end parse string into json.
#enjoy
I am trying to upload a video from android device to server using Retrofit2 and end up getting error '400 Bad Request'. Below is the implementation. Could somebody help to fix the error?
public interface RetrofitService {
/**
* Upload Videos to Server
*/
#Multipart
#POST("store/S3")
Call<ResponseBody> uploadToServer(#Query("key") String ServerAPI,
#Query("mimetype") String videoMimeType,
#Query("path") String path,
#Query("container") String container,
#Query("policy") String policy,
#Query("signature") String signature,
#Part MultipartBody.Part video,
#Part("type") String videoType,
#Part("name") String videoName );
}
Client implemetation in helper.java
private void uploadVideos(String videUri, String policy, String signature){
String BASE_URL = "https://www.example.com/api/";
String EXAMPLE_API_KEY = "xebfc";
String mimeType = "video/mp4";
String path = "mezzanine_videos/";
String container = S3_BUCKET;
// use the FileUtils to get the actual file by uri
File videoFile = new File(videoUri);
// create RequestBody instance from file
RequestBody videoBody = RequestBody.create(MediaType.parse("video/*"), videoFile);
// MultipartBody.Part is used to send the actual file
MultipartBody.Part vFile = MultipartBody.Part.createFormData("video", videoFile.getName(), videoBody);
String videoType = "video/mp4";
String videoName = "video.mp4";
final Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();
RetrofitService service = retrofit.create(RetrofitService.class);
Call<ResponseBody> call = service.uploadToServer( EXAMPLE_API_KEY, mimeType, path, container, policy, signature, vFile, videoType, videoName);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Log.d("Response", "Successful Response");
}
#Override
public void onFailure(Call call, Throwable t) {
Log.d("Response", "Failure Response");
}
}); }
Server implementation works fine because I get a valid response by doing a curl post like below.
curl -X POST -F fileUpload=#animation.mov "https://www.example.com/api/store/S3?key= xebfc&mimetype=video%2Fmp4&path=mezzanine_videos/&container= S3_BUCKET&policy=ppppp&signature=ssss
After some debugging on MultipartBody.Part.createFormData, figured out that the name was not matching with my backend implementation. Below code fixed the issue.
MultipartBody.Part vFile = MultipartBody.Part.createFormData("fileUpload", videoFile.getName(), fileBody);
Rest of the code is same as mentioned above.
Image Multipart in class type object.
case 1. (Which I had done)
Service params:
{"id":"1","name":"vishal","image/file":""}
At that time my API of Retrofit
#Multipart
#POST("webservice")
Call<SignUpResp> loadSignupMultipart(#Part("description") RequestBody description, #Part MultipartBody.Part file, #QueryMap HashMap<String, String> params);
case 2. (Where I have Problem) with #Body class<UploadwithImage>
{
"methodName":"submitLevel1Part2Icon",
"userid":"150",
"headerData":{
"fiction":{
"icon_type":"1",
"icon_id":"3"},
"nonfiction":{
"icon_type":"2",
"icon_id":"4"},
"relation":{
"icon_type":"3",
"icon_id":"0",
"name":"Ronak",
"relative_image":"<File>",
"relation_id":"3"},
"self":{
"icon_type":"4",
"icon_id":"0"}
}
}
I am trying this API
#Multipart
#POST("webservice")
Call<SubmitLevel1Part2IconResp> loadLevel1halfIconswithImage(#Part("description") RequestBody description, #Part MultipartBody.Part file, #Body UploadwithImage uploadImage);
Java side
/**
* code for multipart
*/
// create RequestBody instance from file
RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), fileUpload);
// MultipartBody.Part is used to send also the actual filename
MultipartBody.Part body = MultipartBody.Part.createFormData("methodName[headerData][relation][relative_image]", fileUpload.getName(), requestFile);
// add another part within the multipart request
String descriptionString = "hello, this is description speaking";
RequestBody description = RequestBody.create(MediaType.parse("multipart/form-data"), descriptionString);
call = service.loadLevel1halfIconswithImage(description, body, levelOneHalfIcons);
I don't know why but it returns error like:
"#Body parameters cannot be used with form or multi-part encoding"
Any Help would Be Appreciated.
Change your method to
#Multipart
#POST("users/{id}/user_photos")
Call<models.UploadResponse> uploadPhoto(#Path("id") int userId, #PartMap Map<String, RequestBody> params);
Now to create your request parameters,
//All the String parameters, you have to put like
Map<String, RequestBody> map = new HashMap<>();
map.put("methodName", toRequestBody(methodName));
map.put("userid", toRequestBody(userId));
map.put("relation", toRequestBody(relation));
map.put("icon_type", toRequestBody(iconType));
map.put("icon_id", toRequestBody(iconId));
map.put("name", toRequestBody(name));
map.put("relation_id", toRequestBody(relationId));
//To put your image file you have to do
File file = new File("file_name");
RequestBody fileBody = RequestBody.create(MediaType.parse("image/png"), file);
map.put("relative_image\"; filename=\"some_file_name.png\"", fileBody);
// This method converts String to RequestBody
public static RequestBody toRequestBody (String value) {
RequestBody body = RequestBody.create(MediaType.parse("text/plain"), value);
return body ;
}
//To send your request
call = service.loadLevel1halfIconswithImage(description, params);
In case you do not want to use PartMap, you can simply pass them as parameters. Check my answer https://stackoverflow.com/a/37052548/1320616 to get some clue on sending image file with request.
As simple way, I have done like this:
I have tested by changing
Call<Result> resultCall = service.uploadImage(body);
to
Call<Result> resultCall = service.uploadImage(body, result); where result is
Result.java class (Response) of my API:
public class Result {
#SerializedName("result")
#Expose
private String result;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
#SerializedName("value")
#Expose
private String value;
/**
* #return The result
*/
public String getResult() {
return result;
}
/**
* #param result The result
*/
public void setResult(String result) {
this.result = result;
}
}
and created object like:
Result result = new Result();
result.setResult("success");
result.setValue("my value");
You can change your class as per your need then pass object when you send request. So your ApiService class will be like:
ApiService.java
/**
* #author Pratik Butani on 23/4/16.
*/
public interface ApiService {
/*
Retrofit get annotation with our URL
And our method that will return us the List of Contacts
*/
#Multipart
#POST("upload.php")
Call<Result> uploadImage(#Part MultipartBody.Part file, #Part("result") Result result);
}
and My PHP code is:
<?php
$file_path = "";
$var = $_POST['result']; //here I m getting JSON
$file_path = $file_path . basename( $_FILES['uploaded_file']['name']);
if(move_uploaded_file($_FILES['uploaded_file']['tmp_name'], $file_path)) {
$result = array("result" => "success", "value" => $var);
} else{
$result = array("result" => "error");
}
echo json_encode($result);
?>
Hope it will helps you. Thank you.
You can also use a Map with RequestBody as value and string as keys to add parameters and you can send this using Multipart and PartMap.
Check the following code, hope it will help :
#Multipart
#POST("/add")
Call<ResponseBody> addDocument(#PartMap Map<String,RequestBody> params);
Map<String, RequestBody> map = new HashMap<>();
map.put("user_id", RequestBody.create(MediaType.parse("multipart/form-data"), SessionManager.getInstance().getCurrentUserId()));
map.put("doc_name", RequestBody.create(MediaType.parse("multipart/form-data"), CommonUtils.removeExtension(textFile.getName())));
map.put("doc_category", RequestBody.create(MediaType.parse("multipart/form-data"), category));
map.put("doc_image_file", RequestBody.create(MediaType.parse("multipart/form-data"), imageFile));
map.put("doc_text_content", RequestBody.create(MediaType.parse("multipart/form-data"), body));
map.put("doc_update_time", RequestBody.create(MediaType.parse("multipart/form-data"), "" + new Date(textFile.lastModified())));
We can add all request parameter in multipart body builder with specified type like in below one image file. I have set media type parse multipart/form-data and some other parameter I have set media type parse text/plain. This builder will build to make Multipart Body and can send by using body annotation in multipart body.
#Multipart
#POST("user/update")
Call<ResponseBody> addDocument(##Part MultipartBody file);
final MultipartBody.Builder requestBodyBuilder = new MultipartBody.Builder()
.setType(MultipartBody.FORM);
requestBodyBuilder.addFormDataPart("doc_image_file", imageFile.getName(),
RequestBody.create(MediaType.parse("multipart/form-data"), imageFile));
requestBodyBuilder.addFormDataPart("user_id", null, RequestBody.create(MediaType.parse("text/plain"),"12"));
requestBodyBuilder.addFormDataPart("doc_name", null, RequestBody.create(MediaType.parse("text/plain"),"myfile"));
requestBodyBuilder.addFormDataPart("doc_category", null, RequestBody.create(MediaType.parse("text/plain"),category));
requestBodyBuilder.addFormDataPart("doc_image_file", imageFile.getName(),RequestBody.create(MediaType.parse("multipart/form-data"),imageFile));
requestBodyBuilder.addFormDataPart("doc_text_content", null, RequestBody.create(MediaType.parse("text/plain"),body));
RequestBody multipartBody = requestBodyBuilder.build();
Here is my json request format is :
{
"task":{
"category_id":"1",
"price":"10",
"description":"1",
"task_videos_attributes":[
{
"link":"video file goes here",
"size":"100x100"
}
]
}
}
// my request becomes
HashMap<String, RequestBody> task = new HashMap();
task.put("task[category_id]", createPartFromString(categoryId));
task.put("task[price]", createPartFromString("" + etPrice.getText().toString()));
task.put("task[description]", createPartFromString("" + etDescription.getText().toString()));
// for videos file list
final List<MultipartBody.Part> body = new ArrayList<>();
for (int i = 0; i < videos.size(); i++) {
task.put("task[task_videos_attributes][" + i+ "][size]", createPartFromString("100x100"));
File videoFile = new File(videos.get(i));
RequestBody requestBody = RequestBody.create(MediaType.parse("video/mp4"), videoFile);
MultipartBody.Part fileToUpload = MultipartBody.Part.createFormData("task[task_videos_attributes][" + i + "][link]", videoFile.getName(), requestBody);
body.add(fileToUpload);
}
// here is a final call
new RestClient(this).getInstance().get().postTask(body, task).enqueue(callback);
// This function converts my string to request body
#NonNull
private RequestBody createPartFromString(String descriptionString) {
if (descriptionString == null)
return RequestBody.create(MultipartBody.FORM, "");
return RequestBody.create(
MultipartBody.FORM, descriptionString);
}
Hope this helps you...
Just follow how the web browser is doing multipart. They put nested keys in "[]" and give key to the images too.
Call<SubmitLevel1Part2IconResp> loadLevel1halfIconswithImage(#Part("headerdata[relation][icon_type]") RequestBody icon_type, #Part("headerdata[relation][name]") RequestBody name, #Part MultipartBody.Part file);
And then in java
// MultipartBody.Part is used to send also the actual filename
MultipartBody.Part body = MultipartBody.Part.createFormData("headerdata[relation][relative_image]", fileUpload.getName(), requestFile);
call = service.loadLevel1halfIconswithImage(icon_type, name, body);
https://www.linkedin.com/pulse/retrofit-2-how-upload-multiple-files-server-mahesh-gawale
I guess the best answer to this question can be found here. It worked perfectly for me.
This is the example of uploading an array of files using retrofit in Android.
This is how the service will look like
public interface ApiService {
#POST("/event/store")
Call<ResModel> event_store(#Body RequestBody file);
}
This is how the Client class look like
public class ApiClient {
public static final String API_BASE_URL = "api base url";
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 ApiService createService(Class<ApiService> serviceClass)
{
Retrofit retrofit = builder.client(httpClient.build()).build();
return retrofit.create(serviceClass);
}
}
Upload like this in activity or fragment or where you want
ApiService service = ApiClient.createService(ApiService.class);
MultipartBody.Builder builder = new MultipartBody.Builder();
builder.setType(MultipartBody.FORM);
builder.addFormDataPart("event_name", "xyz");
builder.addFormDataPart("desc", "Lorem ipsum");
// Single Image
builder.addFormDataPart("files",file1.getName(),RequestBody.create(MediaType.parse("image/*"), file1));
// Multiple Images
for (int i = 0; i <filePaths.size() ; i++) {
File file = new File(filePaths.get(i));
RequestBody requestImage = RequestBody.create(MediaType.parse("multipart/form-data"), file);
builder.addFormDataPart("event_images[]", file.getName(), RequestBody.create(MediaType.parse("multipart/form-data"), file));
}
MultipartBody requestBody = builder.build();
Call<ResModel> call = service.event_store(requestBody);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Toast.makeText(getBaseContext(),"All fine",Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Toast.makeText(getBaseContext(),t.getMessage(),Toast.LENGTH_SHORT).show();
}
});
Note: filePaths.size() is a Arraylist of pickup Images Paths.
I hope this post is useful to you. kindly share your feedback as a comment here.
this works for me.
What I did was add every additional params using:
MultipartBody.Part Partname = MultipartBody.Part.createFormData("ParamName", "Value");
Mabe you don't need to create another body, but just add others params apart from the file or whatever you are sending. finally at the interface I put as a params every bodypart that I need.
#Multipart
#POST("api/service/uploadVideo")
Call<ResponseBody> uploadVideoToServer(
#Part MultipartBody.Part video,
#Part MultipartBody.Part param2,
#Part MultipartBody.Part param3 ....
);
I'm trying upload a Image from my Android APP to Amazon AWS S3 and I need use AWS Restful API.
I'm using Retrofit 2 to make to the request.
My application is connecting successfully with Amazon S3 and performing the request as expected, but when I try to view the Image from the Bucket, the picture does not open. I downloaded the Image to my pc and tried to open but keep getting the message that the image is corrupted.
Lets see my complete code bellow.
My Gradle dependencies
compile 'com.squareup.retrofit:retrofit:2.0.0-beta1'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta1'
compile 'net.danlew:android.joda:2.8.2'
Here is created a File and starts the request
File file = new File(mCurrentPhotoPath);
RequestBody body = RequestBody.create(MediaType.parse("image/jpeg"), file);
uploadImage(body, "photo_name.jpeg");
Retrofit Interface
public interface AwsS3 {
#Multipart
#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,
#Part("Body") RequestBody body);
}
Utils class to the mount the credentials
public class AWSOauth {
public static String getOAuthAWS(Context context, String fileName) throws Exception{
String secret = context.getResources().getString(R.string.s3_secret);
String access = context.getResources().getString(R.string.s3_access_key);
String bucket = context.getResources().getString(R.string.s3_bucket);
return gerateOAuthAWS(secret, access, bucket,fileName);
}
private static String gerateOAuthAWS(String secretKey, String accessKey, String bucket, String imageName) throws Exception {
String contentType = "image/jpeg";
DateTimeFormatter fmt = DateTimeFormat.forPattern("EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z").withLocale(Locale.US);
String ZONE = "GMT";
DateTime dt = new DateTime();
DateTime dtLondon = dt.withZone(DateTimeZone.forID(ZONE)).plusHours(1);
String formattedDate = dtLondon.toString(fmt);
String resource = "/" + bucket + "/" + imageName;
String stringToSign = "PUT" + "\n\n" + contentType + "\n" + formattedDate + "\n" + resource;
Mac hmac = Mac.getInstance("HmacSHA1");
hmac.init(new SecretKeySpec(secretKey.getBytes("UTF-8"), "HmacSHA1"));
String signature = ( Base64.encodeToString(hmac.doFinal(stringToSign.getBytes("UTF-8")), Base64.DEFAULT)).replaceAll("\n", "");
String oauthAWS = "AWS " + accessKey + ":" + signature;
return oauthAWS;
}
}
Lastly the method to make a request
public void uploadImage(RequestBody body, String fileName){
String bucket = getString(R.string.s3_bucket);
Retrofit restAdapter = new Retrofit.Builder()
.baseUrl("http://" + bucket + ".s3.amazonaws.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
AwsS3 service = restAdapter.create(AwsS3.class);
DateTimeFormatter fmt = DateTimeFormat.forPattern("EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z").withLocale(Locale.US);
String ZONE = "GMT";
DateTime dt = new DateTime();
DateTime dtLondon = dt.withZone(DateTimeZone.forID(ZONE)).plusHours(1);
String formattedDate = dtLondon.toString(fmt);
try {
String oauth = AWSOauth.getOAuthAWS(getApplicationContext(), fileName);
Call<String> call = service.upload(fileName, body.contentLength(), "/**", bucket + ".s3.amazonaws.com", formattedDate, body.contentType().toString(), oauth, body);
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Response<String> response) {
Log.d("tag", "response : " + response.body());
}
#Override
public void onFailure(Throwable t) {
Log.d("tag", "response : " + t.getMessage());
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
I appreciate any helps, thanks in advance!
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();
}
});
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
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 haven't used Retrofit 2, just Retrofit 1, so YMMV, but I believe that the typical way to do what you're trying to do is to use TypedFile where you are attempting to use RequestBody.
I'm guessing that Retrofit uses RequestBody internally.
You would create the TypedFile something like:
TypedFile typedFile = new TypedFile("multipart/form-data", new File("path/to/your/file"));
and your interface would be:
#Multipart
#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,
#Part("Body") TypedFile body);
}
There's a decent example at
https://futurestud.io/blog/retrofit-how-to-upload-files/
You can use retrofit 2 to upload the image/file
#Multipart
#POST("/api/attachment")
Call<JsonPrimitive> addAttachment(#Part MultipartBody.Part imageFile);
Now to make the call:
RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file);
MultipartBody.Part imageFileBody = MultipartBody.Part.createFormData("file", file.getName(), requestBody);
Note : Make sure you are using retrofit2 as for some reason I was unable to upload image using retrofit1 library.