5

I am using Apache HttpComponents v4.3.3 (maven httpclient and httpmime). I need to upload a file with some metadata. The curl command, which works, looks like the following.

curl -k -i -H "Content-Type: multipart/mixed" -X POST --form 'field1=val1' --form 'field2=val2' --form 'file=@somefile.zip;type=application/zip' https://www.some.domain/

I have tried mimicking this curl post as the following.

HttpEntity entity = MultiPartEntityBuilder
 .create()
 .addPart("field1",new StringBody("val1",ContentType.TEXT_PLAIN))
 .addPart("field2",new StringBody("val2",ContentType.TEXT_PLAIN))
 .addPart("file", new FileBody(new File("somefile.zip"), ContentType.create("application/zip"))
 .build();
HttpPost post = new HttpPost("https://www.some.domain");
post.addHeader("Content-Type", "multipart/mixed");

However, after I use HttpClient to execute the HttpPost, I get the following exception (server code is also Java running on Jetty).

org.apache.commons.fileupload.FileUploadException: the request was rejected because no multipart boundary was found

When I add a trace to curl

curl --trace - -k -i -H "Content-Type: multipart/mixed" -X POST --form 'field1=val1' --form 'field2=val2' --form 'file=@somefile.zip;type=application/zip' https://www.some.domain/

I see that the form field/value pairs are set as HTTP headers.

Content-Disposition: form-data; name=field1...value1

Any idea on what I'm doing wrong here? Any help is appreciated.

Jane Wayne
  • 8,205
  • 17
  • 75
  • 120

2 Answers2

7

I tinkered a bit and did two things to get the code working.

  • no longer use addPart(...)
  • no longer set Content-Type header

Here's the revised snippet that's working in case anyone is interested.

HttpEntity entity = MultipartEntityBuilder
 .create()
 .addTextBody("field1","val1")
 .addTextBody("field2","val2")
 .addBinaryBody("file", new File("somefile.zip"),ContentType.create("application/zip"),"somefile.zip")
 .build();
HttpPost post = new HttpPost("https://www.some.domain");
post.setEntity(entity);

I also set HttpComponents to debug mode.

-Dorg.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
-Dorg.apache.commons.logging.simplelog.showdatetime=true
-Dorg.apache.commons.logging.simplelog.log.org.apache.http=DEBUG

It turns out that each part now has a boundary. Even better yet, the Content-Type and boundary are autogenerated.

Content-Type: multipart/form-data; boundary=5ejxpaJqXwk2n_3IVZagQ1U0_J_X9MdGvst9n2Tc

Jane Wayne
  • 8,205
  • 17
  • 75
  • 120
  • Don't know why you didn't get any votes - this is THE solution for multipart on Android! Other stuff I found did it all manually which is quite cumbersome.... – Lonzak Oct 23 '14 at 16:24
  • 4
    But this is not multipart/mixed. There seem to be hundreds of answers how to do it with multipart/form-data. – unwichtich Sep 02 '16 at 13:41
1

Here my full code based in last response, but is slightly different, i had the same error but now works (thanks Jane!):

public String sendMyFile(String p_file, String p_dni, String p_born_date) throws Exception {

    HttpClient httpclient = HttpClientBuilder.create().build();

    HttpPost    httppost = new HttpPost("http://localhost:2389/TESTME_WITH_NETCAT");

    /* Campos del formulario del POST que queremos hacer */
    File        fileIN  = new File(p_file);

    /* Construimos la llamada */
    MultipartEntityBuilder reqEntity = MultipartEntityBuilder.create();

    reqEntity
            .setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
            .addBinaryBody  ("p_file"               , fileIN)
            .addTextBody    ("p_dni"                , p_dni)
            .addTextBody    ("p_born_date"  , p_born_date);

    httppost.setEntity(reqEntity.build());

    System.out.println("executing request " + httppost.getRequestLine());

    HttpResponse response = httpclient.execute(httppost);

    System.out.println("1 ----------------------------------------");
    System.out.println(response.getStatusLine());
    System.out.println("2 ----------------------------------------");
    System.out.println(EntityUtils.toString(response.getEntity()));
    System.out.println("3 ----------------------------------------");

    HttpEntity resEntity = response.getEntity();

    if (resEntity != null) {
        System.out.println("Response content length: " + resEntity.getContentLength());
    }

    return "OK";
}
nugbe
  • 139
  • 1
  • 5
  • 1
    Welcome to Stack Overflow! While this code snippet may solve the question, [including an explination](http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) really helps to improve the quality of your post. Remember that you are answering the questions for readers in the future, and those people might not know the reasons for your code suggestion. – gunr2171 Nov 16 '14 at 15:41