Sending image file with retrofit 2

2019-09-13 01:43发布

问题:

I am trying to upload an image to our project's server using Retrofit 2

The image is picked through an image picking activity and seems to work since the file (image) can be displayed using Picasso.

Retrofit succeeds however the server doesn't seem to get the file. Here is the server side part.

func (c *gin.Context) {
   file, header , err := c.Request.FormFile("profileImage")
   // err = http: no such file
}

Sever side error message

Even the RequestBody prints coherent information when I tested it (size, image type...)

Service :

@Multipart
@PATCH("/user/profileImage")
Call<ResponseBody> modifyUserImage(@Part("profileImage") RequestBody profileImage, @Part("userID") RequestBody userID);

Following code is part of the same Fragment class

Opening image picking activity :

Intent getIntent = new Intent(Intent.ACTION_GET_CONTENT);
getIntent.setType("image/*");

Intent pickIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
pickIntent.setType("image/*");

Intent chooserIntent = Intent.createChooser(getIntent, "Select Image");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[]{pickIntent});

startActivityForResult(chooserIntent, 1);

On Activity Result:

    @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (resultCode == Activity.RESULT_OK && requestCode == 1) {
        // process the result
        Uri selectedImage = data.getData();
        String wholeID = DocumentsContract.getDocumentId(selectedImage);
        String id = wholeID.split(":")[1];
        String[] column = {MediaStore.Images.Media.DATA};
        String sel = MediaStore.Images.Media._ID + "=?";
        Cursor cursor = getActivity().getContentResolver().
                query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                        column, sel, new String[]{id}, null);
        String filePath = "";
        int columnIndex = cursor.getColumnIndex(column[0]);
        if (cursor.moveToFirst()) {
            filePath = cursor.getString(columnIndex);
        }
        cursor.close();

        file = new File(filePath);
        Picasso
                .with(getActivity().getApplicationContext())
                .load(file)
                .into(civ_userProfilePicture);
    }
}

Request :

Call<ResponseBody> call = ServiceSingelton.getmInstance().getService()
                        .modifyUserImage(RequestBody.create(MediaType.parse("image/*"), file),
                                         RequestBody.create(MediaType.parse("text/plain"), ServiceSingelton.getmInstance().getUserID()));

call.enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
        if (response.code() == 200) {
            Log.d("RETROFIT SUCCESS", "Pic should be sent");
        } else {
            Log.d("RETROFIT SUCCESS", "Error code received modifying user");
        }
    }

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        Log.d("RETROFIT ERROR", t.getMessage());
    }
});

回答1:

Someone gave me this fix which worked :

To post a part with filename, you should change @Part("profileImage") RequestBody profileImage to @Part RequestBody profileImage, and pass it MultipartBody.Part.createFormData(partName, filename, requestBody):

// Service
@Multipart
@PATCH("/user/profileImage")
Call<ResponseBody> modifyUserImage(@Part MultipartBody.Part profileImage, @Part("userID") RequestBody userID);

// Call
MultipartBody.Part imagePart = MultipartBody.Part.createFormData("profileImage", file.getName(), RequestBody.create(MediaType.parse("image/*"), file));
Call<ResponseBody> call = ServiceSingelton.getmInstance().getService()
                        .modifyUserImage(imagePart,
                                         RequestBody.create(MediaType.parse("text/plain"), ServiceSingelton.getmInstance().getUserID()));