diogo.abdalla
diogo.abdalla

Reputation: 644

File upload with okhttp

Im finishing this project which is using okhttp for communication with a webservice.

All is going fine for regular GETs and POSTs, but I'm not being able to properly upload a file.

The okhttp docs are very lacking on these subjects and everything I found here or anywhere don't seem to work in my case.

It's supposed to be simple: I have to send both the file and some string values. But I can't figured out how to do it.

Following the some samples I found, I first tried this:

RequestBody requestBody = new MultipartBuilder().type(MultipartBuilder.FORM)
    .addFormDataPart("group", getGroup())
    .addFormDataPart("type", getType())
    .addFormDataPart("entity", Integer.toString(getEntity()))
    .addFormDataPart("reference", Integer.toString(getReference()))
    .addPart(Headers.of("Content-Disposition", "form-data; name=\"task_file\""), RequestBody.create(MediaType.parse("image/png"), getFile()))
    .build();

It gives me a "400 bad request" error.

So I tried this from the okhttp recipes:

RequestBody requestBody = new MultipartBuilder().type(MultipartBuilder.FORM)
    .addPart(Headers.of("Content-Disposition", "form-data; name=\"group\""), RequestBody.create(null, getGroup()))
    .addPart(Headers.of("Content-Disposition", "form-data; name=\"type\""), RequestBody.create(null, getType()))
    .addPart(Headers.of("Content-Disposition", "form-data; name=\"entity\""), RequestBody.create(null, Integer.toString(getEntity())))
    .addPart(Headers.of("Content-Disposition", "form-data; name=\"reference\""), RequestBody.create(null, Integer.toString(getReference())))
    .addPart(Headers.of("Content-Disposition", "form-data; name=\"task_file\""), RequestBody.create(MediaType.parse("image/png"), getFile()))
    .build();

Same result.

Don't know what else to try or what look into to debug this.

The request is done with this code:

// adds the required authentication token
Request request = new Request.Builder().url(getURL()).addHeader("X-Auth-Token", getUser().getToken().toString()).post(requestBody).build();
Response response = client.newCall(request).execute();

But Im pretty sure that the problem is how Im building the request body.

What am I doing wrong?

EDIT: "getFile()" above returns the a File object, by the way. The rest of the parameters are all strings and ints.

Upvotes: 9

Views: 18626

Answers (3)

Oyewo Remi
Oyewo Remi

Reputation: 426

Here is how to upload file using okhttp3.

      try {

          UpdateInformation("yourEmailAddress", filePath, sourceFile);

          } catch (IOException e) {
                        e.printStackTrace();
         }

    private void UploadInformation(String email, final String _filePath, final File file) throws IOException {


        runOnUiThread(new Runnable() {
            @Override
            public void run() {


            //show progress bar here

            }
        });


        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(60, TimeUnit.SECONDS)
                .writeTimeout(60, TimeUnit.SECONDS)
                .readTimeout(60, TimeUnit.SECONDS)
                .build();





        String mime = getMimeType(_filePath);


        RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM)
                .addFormDataPart("file", file.getName(),
                        RequestBody.create(MediaType.parse(mime), file))
                .addFormDataPart("email", email)
                .build();





        okhttp3.Request request = new okhttp3.Request.Builder()
                .url("yourEndPointURL")
                .post(body)
                .addHeader("authorization", "yourEndPointToken")
                .addHeader("content-type", "application/json")
                .build();



        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                call.cancel();


                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {

                    //hide progress bar here

                    }
                });

            }

            @Override
            public void onResponse(Call call, okhttp3.Response response) throws IOException {


                try {

                    final String myResponse = response.body().string();


                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {

                    //hide progress bar here

                    //Cont from here
                    //Handle yourEndPoint Response.



                        }
                    });


                } catch (Exception e) {
                    e.printStackTrace();
                }


            }



        });
    }


private String getMimeType(String path) {
        FileNameMap fileNameMap = URLConnection.getFileNameMap();
        String contentTypeFor = fileNameMap.getContentTypeFor(path);
        if (contentTypeFor == null)
        {
            contentTypeFor = "application/octet-stream";
        }
        return contentTypeFor;
    }

Hope this helps.

Upvotes: 0

Pratik Butani
Pratik Butani

Reputation: 62419

I just changed addFormDataPart instead addPart and Finally solved My Problem Using following code:

  /**
     * Upload Image
     *
     * @param memberId
     * @param sourceImageFile
     * @return
     */
    public static JSONObject uploadImage(String memberId, String sourceImageFile) {

        try {
            File sourceFile = new File(sourceImageFile);

            Log.d(TAG, "File...::::" + sourceFile + " : " + sourceFile.exists());

            final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");

            RequestBody requestBody = new MultipartBuilder()
                    .type(MultipartBuilder.FORM)
                    .addFormDataPart("member_id", memberId)
                    .addFormDataPart("file", "profile.png", RequestBody.create(MEDIA_TYPE_PNG, sourceFile))
                    .build();

            Request request = new Request.Builder()
                    .url(URL_UPLOAD_IMAGE)
                    .post(requestBody)
                    .build();

            OkHttpClient client = new OkHttpClient();
            Response response = client.newCall(request).execute();
            return new JSONObject(response.body().string());

        } catch (UnknownHostException | UnsupportedEncodingException e) {
            Log.e(TAG, "Error: " + e.getLocalizedMessage());
        } catch (Exception e) {
            Log.e(TAG, "Other Error: " + e.getLocalizedMessage());
        }
        return null;
    }

Upvotes: 7

diogo.abdalla
diogo.abdalla

Reputation: 644

I found answer to my own question a bit after initial post.

I´ll leave it here, because it can be useful to others, given that there is such a few okhttp upload examples around:

RequestBody requestBody = new MultipartBuilder().type(MultipartBuilder.FORM)
        .addFormDataPart("group", getGroup())
        .addFormDataPart("type", getType())
        .addFormDataPart("entity", Integer.toString(getEntity()))
        .addFormDataPart("reference", Integer.toString(getReference()))
        .addFormDataPart("task_file", "file.png", RequestBody.create(MediaType.parse("image/png"), getFile()))
                                                .build();

There is no reason to use "addPart" with "Headers.of" etc like in the recipes, addFormDataPart does the trick.

And for the file field itself, it takes 3 arguments: name, filename and then the file body. That's it.

Upvotes: 22

Related Questions