3

I have problem with upload photo on server with uses retrofit 2.Can somebody help me? what i did wrong? my back-end dev has sad me that boundary in header didnt generate =( this is my interface:

import retrofit2.http.Headers;
import retrofit2.http.POST;
import retrofit2.http.Part;
import retrofit2.Call;
import retrofit2.http.Multipart;
import okhttp3.MultipartBody;
import com.google.gson.JsonElement;

public interface Retrofitv2Api {
    @Multipart
    @Headers("Content-Type: multipart/form-data;")
    @POST("/mobile/v1/classifieds/UploadImage")
    Call<JsonElement> UploadImage(@Part MultipartBody.Part body,@Part("uniqId")String uniqId,@Part("token")String token);}

builder:

import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class RetrofitV2Config {
    private  static Retrofit getRetrofit(){
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("http://api.qrz.ru")
            .addConverterFactory(GsonConverterFactory.create())
            .build();
        return retrofit;
    }

    public static Retrofitv2Api getService(){
        return getRetrofit().create(Retrofitv2Api.class);
    }

and upload fragment:

String photoPath = photoAdapter.getPhotoPaths().get(0);
                File image = new File(photoPath);


                RequestBody imageBody = RequestBody.create(MediaType.parse("image/*"), image);

                MultipartBody.Part body =  MultipartBody.Part.createFormData("file", image.getName(), imageBody);


                RetrofitV2Config.getService().UploadImage(body , "2536654", Token.getSavedToken()).enqueue(new Callback<JsonElement>() {
                    @Override
                    public void onResponse(Call<JsonElement> call, Response<JsonElement> response) {
                        Log.i(Logger.TAG, "onResponseUpload " + response.body() + " " + response.code());
                    }

                    @Override
                    public void onFailure(Call<JsonElement> call, Throwable t) {
                        Log.i(Logger.TAG, "onFailureUpload");
                    }
                });

backend ansver:

21:34:32.386117 IP 46.37.203.69.50461 > 62.181.46.35.http: Flags [P.], seq 1184070465:1184071311, ack 3418438796, win 65535, length 846
E..v.o@.5....%.E>..#...PF.{A..<.P...]...POST /mobile/v1/classifieds/UploadImage HTTP/1.1
Content-Type: multipart/form-data
Content-Length: 647
Host: api.qrz.ru
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/3.2.0

--950f42dd-12a1-4e11-a3b0-826ddaf41aa3
Content-Disposition: form-data; name="img"
Content-Transfer-Encoding: binary
Content-Type: application/json; charset=UTF-8
Content-Length: 2

{}
--950f42dd-12a1-4e11-a3b0-826ddaf41aa3
Content-Disposition: form-data; name="uniqId"
Content-Transfer-Encoding: binary
Content-Type: application/json; charset=UTF-8
Content-Length: 8

"215132"
--950f42dd-12a1-4e11-a3b0-826ddaf41aa3
Content-Disposition: form-data; name="token"
Content-Transfer-Encoding: binary
Content-Type: application/json; charset=UTF-8
Content-Length: 22
Mazda Doc
  • 51
  • 5
  • Please read http://stackoverflow.com/questions/36491096/retrofit-multipart-request-required-multipartfile-parameter-file-is-not-pre/36514662#36514662 – BNK Apr 12 '16 at 03:27

4 Answers4

1

Thank you all ! I find the solution.In my case I should use MultipartBody.Part instead String in interface Retrofitv2Api

public interface Retrofitv2Api {
@Multipart
@POST("/mobile/v1/classifieds/UploadImage")
Call<UploadPhoto> UploadImage(@Part MultipartBody.Part body,@Part MultipartBody.Part uniqId,@Part MultipartBody.Part token);}

File image = new File(path);

        RequestBody imageBody = RequestBody.create(MediaType.parse("image/jpeg"), image);

        MultipartBody.Part body = MultipartBody.Part.createFormData("img", image.getName(), imageBody);
        MultipartBody.Part uniqID = MultipartBody.Part.createFormData("uniqId", uniqId);
        MultipartBody.Part token = MultipartBody.Part.createFormData("token", Token.getSavedToken());

        Call<UploadPhoto> call = RetrofitV2Config.getService().UploadImage(body, uniqID, token);
        call.enqueue(new Callback<UploadPhoto>() {
            @Override
            public void onResponse(Call<UploadPhoto> call,
                                   Response<UploadPhoto> response) {
                Log.v("Upload", "success: " + response.raw().toString());

            }

            @Override
            public void onFailure(Call<UploadPhoto> call, Throwable t) {
                Log.e("Upload error:", t.getMessage());

            }
        });
Mazda Doc
  • 51
  • 5
0

Try to use TypedFile instead MultipartBody, something like this:

String photoPath = photoAdapter.getPhotoPaths().get(0);
  try {
        File image = new File(getApplicationContext().getFilesDir().getPath().toString(), "YourFileName");

        // Decode with inSampleSize 
        BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
        bitmapOptions.inSampleSize = calculateInSampleSize(bitmapOptions, 1080, 1080);
        bitmapOptions.inJustDecodeBounds = false;

        Bitmap bitmap = BitmapFactory.decodeFile(photoPath, bitmapOptions);

            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.JPEG, 50, bos);
            byte[] bitmapdata = bos.toByteArray();

            //write the bytes in file
            FileOutputStream fos = new FileOutputStream(image);
            fos.write(bitmapdata);
            fos.flush();
            fos.close();

                // yourImageType means for example .png .jpg etc.
                TypedFile typedFile = new TypedFile("image/yourImageType", image);

      } catch (IOException e) {
      } catch (OutOfMemoryError outOfMemoryError) {
      }


     RetrofitV2Config.getService().UploadImage(typedFile , "2536654", Token.getSavedToken()).enqueue(new Callback<JsonElement>() {
        @Override
        public void onResponse(Call<JsonElement> call, Response<JsonElement> response) {
            Log.i(Logger.TAG, "onResponseUpload " + response.body() + " " + response.code());
        }

        @Override
        public void onFailure(Call<JsonElement> call, Throwable t) {
            Log.i(Logger.TAG, "onFailureUpload");
        }
    });

And change your interface:

   @Multipart
    @Headers("Content-Type: multipart/form-data;")
    @POST("/mobile/v1/classifieds/UploadImage")
    Call<JsonElement> UploadImage(@Part("file") TypedFile file,@Part("uniqId")String uniqId,@Part("token")String token);}
Kristiyan Varbanov
  • 2,439
  • 2
  • 17
  • 37
Ivan Ivanov
  • 902
  • 5
  • 12
0
public interface UploadAvatarService {
    @Multipart
    @POST("user/upload_head")
    Observable<UploadAvatarBean> upload(@Part("file\"; filename=\"image.png\"") RequestBody avatarFile);
}

the Part will code in Retrofit as

Headers headers =
              Headers.of("Content-Disposition", "form-data; name=\"" + partName + "\"",
                  "Content-Transfer-Encoding", part.encoding());

you need set filename to the file.

cs x
  • 621
  • 2
  • 8
  • 23
0

You should use RequestBody instead String

public interface Retrofitv2Api {
@Multipart
@Headers("Content-Type: multipart/form-data;")
@POST("/mobile/v1/classifieds/UploadImage")
Call<JsonElement> UploadImage(@Part MultipartBody.Part body,@Part("uniqId")RequestBody uniqId,@Part("token") RequestBody token);
}


private void UploadImage(File file,String uniqId,String token) {  
// create upload service client
Retrofitv2Api service =
        new RetrofitV2Config().getService();

RequestBody requestFile =
        RequestBody.create(MediaType.parse("multipart/form-data"), file);

// MultipartBody.Part is used to send also the actual file name
MultipartBody.Part body =
        MultipartBody.Part.createFormData("file", file.getName(), requestFile);


// finally, execute the request
Call<ResponseBody> call = service.upload( body,RequestBody.create(
                MediaType.parse("multipart/form-data"), uniqId),RequestBody.create(
                MediaType.parse("multipart/form-data"), token));
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());
    }
});

}

Linkang Ma
  • 177
  • 1
  • 11