Retrofit2 - Upload photo 500 Internal Server error - android

I want to upload a photo using Retrofit2, but I can't get rid of 500 Internal Server error. I also get the message "reduce of empty array with no initial value". When I retrieve the uploaded photos from the server, the photo is not there. I'm using Charles Web Debugging Proxy tool to check the response.
public static void postPhoto(String participantId, String photoPath) {
try {
File photo = new File(photoPath);
ApiEndpoints api = ApiProvider.getInstance().getApiInstance();
RequestBody reqFile = RequestBody.create(MediaType.parse("image/*"), photo);
MultipartBody.Part body = MultipartBody.Part.createFormData("image", photo.getName(), reqFile);
Call<ResponseBody> call = api.uploadPhoto(participantId, body);
call.execute();
} catch (Exception e){
e.printStackTrace();
}
}
API endpoint
#Multipart
#POST("participant/{id}/image")
Call<ResponseBody> uploadPhoto(#Path("id") String id, #Part MultipartBody.Part image);

Related

what is the issue in file uploading using retrofit (pdf,ppt, png,jpg) "code=500, internal server error"

enter image description hereI'm setting up the file uploading function using retrofit but I am getting internal server error. Sometime file is uploading on the server with details but response is coming in error body. I have no idea is there any problem in my code or in server side code.
I have tried different code for request body.
RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
MultipartBody.Part body = MultipartBody.Part.createFormData("pic", file.getName(), requestFile);
File file = new File(PathHolder);
RequestBody requestFile =
RequestBody.create(MediaType.parse("multipart/form-data"), file);
MultipartBody.Part body = MultipartBody.Part.createFormData("pic",
file.getName(), requestFile);
RequestBody userId =
RequestBody.create(MediaType.parse("text/plain"), uid);
RequestBody topic = RequestBody.create(MediaType.parse("text/plain"),
topicName);
RequestBody classID =
RequestBody.create(MediaType.parse("text/plain"), classId);
RequestBody shiftID =
RequestBody.create(MediaType.parse("text/plain"), shiftId);
Call<UploadDocumentResponse> resultCall = service.uploadImage(userId,
topic, classID, shiftID, body);
resultCall.enqueue(new Callback<UploadDocumentResponse>() {
#Override
public void onResponse(Call<UploadDocumentResponse> call,
Response<UploadDocumentResponse> response) {
progressDialog.dismiss();
onBackPressed();
UploadDocumentResponse iresponse = response.body();
// ViewDocModel Success or Fail
if (response.isSuccessful()) {
Toast.makeText(getApplicationContext(), response.body().
getMsg(), Toast.LENGTH_LONG).show();
imageView.setImageDrawable(null);
imagePath = null;
}
}
#Override
public void onFailure(Call<UploadDocumentResponse> call, Throwable t)
{
progressDialog.dismiss();
Toast.makeText(getApplicationContext(), "couldn't upload file,
please try
again", Toast.LENGTH_LONG).show();
}
});
// APIInterface
#Multipart
#POST("Camp/API_uploadfile.php")
Call<UploadDocumentResponse> uploadImage(#Part("uid") RequestBody uid,
#Part("topic") RequestBody
topic,
#Part("classid") RequestBody
classId,
#Part("shiftid") RequestBody
shiftId,
#Part MultipartBody.Part file);
Expected result is file should be upload on server and get response in success.
Actual result is getting internal server error and sometime getting success response message in error body.
I have solved this issue.
I was using wrong pattern of request body. I had to use multipart form data instead of text.
File file1 = new File(imageFilePathFront);
RequestBody requesFile = RequestBody.create(MediaType.parse("multipart.form-
data"), file1);
cnicFront = MultipartBody.Part.createFormData("CNIC_FRONT_IMG",
file1.getName(), requesFile);
This is the right code worked for me.

How to upload images to the server using retrofit 2

I have to upload an image to server using Retrofit2.
Everything has worked fine at first, but after I re-check it before the release the API failed that can't upload the image but still works using postman!
My code is :
MultipartBody.Part imagePart = MultipartBody.Part.createFormData("image",
image.getFilename(), RequestBody.create(MediaType.get(image.getMimeType()), image.getFile()));
RequestBody sessionPart = RequestBody.create(MultipartBody.FORM, sessionToken);
RequestBody userIdPart = RequestBody.create(MultipartBody.FORM, userId);
RequestBody pictureTypePart = RequestBody.create(MultipartBody.FORM, pictureType.pictureTypeValue());
return dubaingNetwork.uploadProfilePic(accessToken,userIdPart,sessionPart,imagePart,pictureTypePart);
My api interface is:
#Multipart
#POST(Urls.UPLOAD_PROFILE_PIC)
Observable<UploadProfilePicResponse> uploadProfilePic(#Header(ACCESS_TOKEN_FIELD_NAME) String accessToken,
#Part(USER_ID_FIELD_NAME) RequestBody userId,
#Part(SESSION_TOKEN_FIELD_NAME) RequestBody sessionToken,
#Part MultipartBody.Part image,
#Part("image_type") RequestBody pictureType);
Edit: I tried to convert it to urlencoded type with the image converted to string Base64 and the parameters as a field but still the same error on phone and in postman still works, so I don't think it's a server-side error

Retrofit 2 file upload does not attach file

I've written a upload action on server using asp core and I've tested that with ARC and files gets received.
But when I try to upload image with Retrofit, nothing gets send. Even the form is empty:
The source Code of interface is here. The interface:
public interface QuestionWebService {
#Multipart
#POST("questionapi/uploadfiles")
Call<ResponseBody> uploadSync(#Part("fileUpload") RequestBody paramTypedFile);
}
and the usage in async task:
#Override
protected Boolean doInBackground(String... params) {
File fileToSend = new File(params[0]);
// fileToSend.renameTo()
RequestBody typedFile = RequestBody.create(MediaType.parse("image/*"), fileToSend);
Response response = restClient.getQuestionService().uploadSync(typedFile).execute();
if (response == null){
Log.e(TAG, "success send server - failed");
return false;
}
if (response.isSuccessful()) {
Log.e(TAG, "success send server - 200 status");
} else {
Log.e(TAG, "success send server - fail status - " + response.toString());
}
} catch (Exception e) {
//throw new RuntimeException(e);
Log.e(TAG,e.getMessage().toString());
return false;
}
return true;
}
Any Idea about what should I try? Where am I Going Wrong.
TG.
Finally I found the solution. I don't know the reason about why this code doesn't work but as this link says, I changed the:
public interface QuestionWebService {
#Multipart
#POST("questionapi/uploadfiles")
Call<ResponseBody> uploadSync(#Part("fileUpload") RequestBody paramTypedFile);
}
to this one:
public interface QuestionWebService {
#Multipart
#POST("questionapi/uploadfiles")
Call<ResponseBody> uploadSync(#Part("UserId") RequestBody UserId, #Part("answer") RequestBody answer, #Part MultipartBody.Part file);
}
and the usage from this:
RequestBody typedFile = RequestBody.create(MediaType.parse("image/*"), fileToSend);
Response response = restClient.getQuestionService().uploadSync(typedFile).execute();
to this one:
// create RequestBody instance from file
RequestBody requestFile =
RequestBody.create(MediaType.parse("multipart/form-data"), fileToSend);
// MultipartBody.Part is used to send also the actual file name
MultipartBody.Part body =
MultipartBody.Part.createFormData("fileUpload", fileToSend.getName(), requestFile);
RequestBody userId =
RequestBody.create(
MediaType.parse("multipart/form-data"), userIdString);
// add another part within the multipart request
String answerString = "hello, this is answer speaking";
RequestBody answer =
RequestBody.create(
MediaType.parse("multipart/form-data"), answerString);
Response response = restClient.getQuestionService().uploadSync(userId, answer, body).execute();
and now every thing goes right!!!
I hope this will the others encounter same problem.
Now the data on server is a form with 2 fields, UserId and Answer, and a file named fileUpload.
TG.

Android send byte array with image using Retrofit2

I have a byte array in my application which I get from camera. I need to send it to server using Retrofit2. When I try send it I get SocketTimeoutException. I've tried also send request using browser and all works fine. Here is my retrofit service method for sending:
#Multipart
#POST("/userchange/setuserpic")
Call<AuthResponse> setUserPic(#Part("authToken") RequestBody authToken, #Part("userpic") RequestBody picture, #Part("extension") RequestBody extension);
I do sending in my service like below:
private void handleActionSetUserPic(String authToken, byte[] picture, String extension) {
RequestBody token = RequestBody.create(MediaType.parse("multipart/form-data"), authToken);
RequestBody pic = RequestBody.create(MediaType.parse("multipart/form-data"), picture);
RequestBody ext = RequestBody.create(MediaType.parse("multipart/form-data"), extension);
Call<AuthResponse> request = mAuthApi.setUserPic(token, pic, ext);
try {
Response<AuthResponse> response = request.execute();
AuthResponse result = response.body();
Log.i("tag", result.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
So what am I doing wrong?

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

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.

Categories

Resources