I'm making an app in which I have to send image from gallery to server.
These should be headers (according to apiary).
Content-Type:image/jpeg
X-Filename:photo.jpg
But in logs in interceptor, there is only X-Filename, even though I tried multiple ways and I'm running out of ideas.
Server responds with 200 but the next call (commit image) returns 500 with error at the end of post.
These are the methods:
#Multipart
#POST("uploads")
Observable<String> uploadImage(
#Header("Content-Type") String contentType,
#Header("X-Filename") String fileName,
#Header("Authorization") String token,
#Part MultipartBody.Part file
);
#GET("uploads/{fileId}/commit")
Observable<String> commitFile(
#Header("Content-Type") String type,
#Header("Authorization") String token,
#Path("fileId") String fileId
);
OkHttp client:
private OkHttpClient createApiClient(Context context) {
int cacheSize = 10 * 1024 * 1024; // 10 MiB
Cache cache = new Cache(context.getCacheDir(), cacheSize);
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.addInterceptor(chain -> {
Request request = chain.request().newBuilder().build();
request.newBuilder().addHeader("Content-Type", "application/json");
Timber.d("Request: [%s] %s", request.method(), request.url());
Timber.d("Request: %s", request.headers().toString());
if (request.body() != null) {
Timber.d("Request: %s", request.body().toString());
}
return chain.proceed(request);
});
builder.cache(cache);
return builder.build();
}
Resulting logs:
D/NetModule: Request: [POST] https://winged-guild-133523.appspot.com/api/v1/uploads
D/NetModule: Request: X-Filename: asura.png
Authorization: HAYVi3clcqjug53IPS6AYMgzCPGnDE3Si
D/NetModule: Request: retrofit2.RequestBuilder$ContentTypeOverridingRequestBody#7c37f46
Same thing happens with Postman - Postman screenshot
Commit fails with this error: (sorry for ugly formatting)
{
"errorCode": "ImagesServiceFailureException",
"errorParam": "",
"errorMessage":"com.google.appengine.api.images.ImagesServiceFailureException: "
}
As I said I'm running out of ideas and would greatly appreciate any help with this upload problem.
(edit) PS: by omitting #Header("Content-Type") String contentType in app and using application/x-www-form-urlencoded in Postman, image upload and commit are both successful, but Image at returned url has no metadata and therefore can't be displayed.
Do not use #Multipart. Instead, use something like this:
#POST("upload/image")
Observable<ResponseBody> uploadImage(#Body RequestBody body);
File imageFile = new File(path);
RequestBody body = RequestBody.create(MediaType.parse("image/jpeg"),imageFile);
api.uploadImage(body);
This is my code using retrofit
#Multipart
#POST(ServiceConfig.API_CREATE_DEPENDENT_ACCOUNT)
#Headers({
"Accept: application/json",
"Accept-Encoding: gzip"
})
Call<DataResponse<CreateDependentAccountResponse>> createDependentAccount(#Query(JioConstants.ParamQuery.TOKEN) String token,
#Query(JioConstants.ParamQuery.USER_ID) long userID,
#Query(JioConstants.ParamQuery.FIRST_NAME) String firstName,
#Query(JioConstants.ParamQuery.LAST_NAME) String lastName,
#Query(JioConstants.ParamQuery.GENDER) String gender,
#Query(JioConstants.ParamQuery.DOB) String dob,
#Query(JioConstants.ParamQuery.RELATIONSHIP_ID) long relationshipID,
#Query(JioConstants.ParamQuery.DISPLAY_UNIT) String displayUnit,
#Part("avatar\"; filename=\"picture.jpg\" ") RequestBody file);
and
RequestBody file = null;
if (mFileTemp != null) {
file = RequestBody.create(MediaType.parse("image/*"), mFileTemp);
} else {
file = RequestBody.create(MediaType.parse("image/*"), "");
}
manageCall(ServiceManager.INSTANCE2().
createDependentAccount(token, userID, firstName, lastName, gender, dob, relationshipID, displayUnit, file))
.enqueue(new SimplifiedCallback<CreateDependentAccountResponse>() {
#Override
public void success(CreateDependentAccountResponse data, String message) {
hideLoading();
Good luck. This is my game
Related
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.
In the Google documentation about it is not written, I use retrofit 2. Help. Write what request should be sent and what parameters to transmit
interface:
#PATCH("drive/v3/files/{fileId}")
#Multipart
Call<ResponseBody> renameFileGoogle(
#Path("fileId")String fileId,
#Part MultipartBody.Part metaPart
);
call metod:
public void renameMetod(String id, String title) {
String content = "{\"name\": \"" + title + "\"}";
MediaType contentType = MediaType.parse("application/json; charset=UTF-8");
MultipartBody.Part metaPart = MultipartBody.Part.create(RequestBody.create(contentType, content));
Call<ResponseBody> renameRequest = server.renameFileGoogle(id, metaPart);
renameRequest.enqueue(new Callback<ResponseBody>()...
It's there in the documentation https://developers.google.com/drive/v2/reference/files/patch
You need to send an HTTP PATCH request
PATCH https://www.googleapis.com/drive/v2/files/{fileId}
RequestBody:
{"title":"newTitle"}
For version 3
https://developers.google.com/drive/v3/reference/files/update
PATCH https://www.googleapis.com/drive/v3/files/{fileId}
RequestBody:
{"name":"newTitle"}
I'm using Retrofit beta2 and I'm struggling on multipart upload. I have tried the code as specified here. I may have missed something here.
public interface SendMediaApiService {
#Multipart
#POST(/api/v1/messages)
Call<ApiResponse> upload(
#Header("Authorization") String token,
#Query("recipient_user_id") String userId,
#Query("message") String message,
#Part("name=\"photo\"; filename=\"selfie.jpg\" ") RequestBody file
);
}
private void upload() {
Retrofit retrofit = new Retrofit.Builder()
// do some stuffs here
File file = new File(filePath);
RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file);
Call<ApiResponse> call = service.upload(token, userId, msg, requestBody);
}
when I curl
$ curl -v \
> -H "Authorization: Bearer TOKEN" \
> -F "photo=#/path/to/my/image.jpg" \
> http://domain.com/api/v1/messages?recipient_user_id=USER_ID&message=test
Maybe, you can delete #Multipart
Just like this,
#POST("/V2/image/{type}")
Call<ImageUrl> uploadImg(#Path("type") int type, #Body RequestBody image);
To create RequestBody, you can use
public static RequestBody createImageRequest(Bitmap bitmap) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
return new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addFormDataPart("file", "test.png", RequestBody.create(MediaType.parse("image/png"), byteArrayOutputStream.toByteArray())).build();
}
When I request with #Multipart, the image file would be put in request body. When without #Multipart, the file in request header.
Little preface: I'm the co-author of the linked blog post.
Your code looks mostly good. A little difference between our tested code and yours is the #Part() RequestBody file declaration. Our code is not specifying the file:
#Part("myfile\"; filename=\"image.png\" ") RequestBody file.
In your code, on the other hand, is:
#Part("name=\"photo\"; filename=\"selfie.jpg\" ") RequestBody file.
I'd suggest to remove the name=\" part from the declaration and try again. If it doesn't help, what's your error?
I have successfully uploaded the image file with Retroft. As what #peitek have suggested to remove the name=\" part solved the issue.
For those people that encountered this difficulty, this code below is working (at least for me). This may serve as your reference.
interface SendMediaApiService {
#Multipart
#POST(/api/v1/messages)
Call<ApiResponse> upload(
#Header("Authorization") String token,
#Query("recipient_user_id") String userId,
#Query("message") String message,
#PartMap Map<String, RequestBody> map
);
}
private void upload() {
Retrofit retrofit = new Retrofit.Builder()
// do some stuffs
Map<String, RequestBody> map = new HashMap<>();
File file = new File(path);
RequestBody requestBody = RequestBody.create(MediaType.parse("image/jpeg"), file);
map.put("photo\"; filename=\"" + file.getName() + "\"", requestBody);
SendMediaApiService service = retrofit.create(SendMediaApiService.class);
Call<ApiResponse> call = service.upload(token, userId, msg, map);
call.enqueue(this);
}
source
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.
In my app I am uploading images to AWS via Retrofit with this code:
private interface UploadFileToAwsInterface {
#Multipart
#POST("/")
SuccessResponse uploadFile(#Part("key") String key,
#Part("AWSAccessKeyId") String AWSAccessKeyId,
#Part("acl") String acl,
#Part("success_action_redirect") String success_action_redirect,
#Part("policy") String policy,
#Part("signature") String signature,
#Part("utf8") String utf8,
#Part("Content-Type") String contType,
#Part("file") TypedFile file);
}
public Boolean uploadFileToAws(AWSCredentials awsCredentials, File localFile, String mimeType) {
TypedFile file = new TypedFile(mimeType, localFile);
endPoint.setUrl(awsCredentials.getAction());
UploadFileToAwsInterface uploadFileInterface = restAdapter.create(UploadFileToAwsInterface.class);
SuccessResponse response = uploadFileInterface.uploadFile(
awsCredentials.getKey(),
awsCredentials.getAWSAccessKeyId(),
awsCredentials.getAcl(),
awsCredentials.getSuccess_action_redirect(),
awsCredentials.getPolicy(),
awsCredentials.getSignature(),
"true",
mimeType,
file);
Image uploading works fine. But when I start image upload and network disconnect, I can't get response. How I can get failure in such situation?
You can catch RetrofitError when you call uploadFileInterface.uploadFile():
try {
SuccessResponse response = uploadFileInterface.uploadFile(
awsCredentials.getKey(),
awsCredentials.getAWSAccessKeyId(),
awsCredentials.getAcl(),
awsCredentials.getSuccess_action_redirect(),
awsCredentials.getPolicy(),
awsCredentials.getSignature(),
"true",
mimeType,
file);
} catch (RetrofitError error) {
//TODO Show exception here
}