You need to send a photo, header and several fields in form-data.

If you send a photo separately, it is sent to the server successfully. (Status 200)

If you send a photo with the form-data fields, the photo does not come to the server, and the fields come. (Status 200).

Help, maybe something is wrong in the code

Postman request works correctly: one

Interface Code:

@Multipart @PATCH("user") Call<UserData> updateUserData(@Header("ACCESS-TOKEN") String accessToken , @QueryMap Map<String, String> stringMap , @Part MultipartBody.Part file); 

Method call code:

 public static void udpateUserDataWithPhoto(Callback<UserData> callback, Map<String, String> map1) { String token = SharedPreferenceStorage.getInstance().getServerAccessToken(); File file = new File(Constants.PATH_TO_PROFILE_PHOTO + "avatar.jpg"); MultipartBody.Part body = prepareFilePart(USER_profile_photo, file); App.getApi().updateUserData(token, map1, body).enqueue(callback); } private static MultipartBody.Part prepareFilePart(String partName, File file) { String mimeType = URLConnection.guessContentTypeFromName(file.getName()); if (mimeType != null) { RequestBody requestFile = RequestBody.create(MediaType.parse(mimeType), file); // MultipartBody.Part is used to send also the actual file name return MultipartBody.Part.createFormData(partName, file.getName(), requestFile); } else { return null; } } 

The code for creating the object Retrofit2:

 OkHttpClient okHttpClient = new OkHttpClient.Builder() .addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)) //logging .build(); retrofit = new Retrofit.Builder() .baseUrl(Constants.BASE_URL) //Базовая часть адреса .addConverterFactory(GsonConverterFactory.create()) //Конвертер, необходимый для преобразования JSON'а в объекты .client(okHttpClient) .build(); iRetrofit = retrofit.create(IRetrofit.class); //Создаем объект, при помощи которого будем выполнять запросы // ... public static IRetrofit getApi() { return iRetrofit; } 

Logs: 2 3

The strangest thing is that when sending 3 fields and a file, the server returns status 200 and accepts strings, but does not accept the file.

In postmen, this query passes without problems (1st picture)

If you send only a file, without 3 of these fields - the server also gives the status 200 and accepts this image file normally. (seen in the logs)

Could it be that the fields conflict with Multipart?

Used library versions

 implementation 'com.squareup.retrofit2:retrofit:2.3.0' implementation 'com.squareup.retrofit2:converter-gson:2.3.0' implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0' 

    1 answer 1

    Based on these articles

    how-to-upload-multiple-files-to-server

    passing-multiple-parts-along-a-file-with-partmap

    Understood that there QueryMap does not approach.

    Changed methods like this:

     @NonNull public static RequestBody createPartFromString(String descriptionString) { return RequestBody.create(MultipartBody.FORM, descriptionString); } public static void udpateUserDataWithPhoto(Callback<UserData> callback, HashMap<String, RequestBody> map) { // метод меняет только входной параметр на HashMap<String, RequestBody> } заполнение массива в метод выше такое: RequestBody pName = RetrofitQueries.createPartFromString("" + userData.getFirstName()); RequestBody pLastname = RetrofitQueries.createPartFromString("" + userData.getLastName()); RequestBody pUsername = RetrofitQueries.createPartFromString("" + userData.getUsername()); HashMap<String, RequestBody> map = new HashMap<>(); map.put(RetrofitQueries.USER_first_name, pName); map.put(RetrofitQueries.USER_last_name, pLastname); map.put(RetrofitQueries.USER_username, pUsername); 

    The interface method has become:

     @Multipart @PATCH("user") Call<UserData> updateUserData(@Header("ACCESS-TOKEN") String accessToken , @PartMap HashMap<String, RequestBody> partMap , @Part MultipartBody.Part file); 

    The point was that when sending a Multipart file, you must send form-data lines also via @Part / @PartMap