I usually post about HTTP stuff on Twitter - you can follow me there:

1. Overview

In this tutorial, we will illustrate how to do a multipart upload operation using HttpClient 4.

We’ll use http://echo.200please.com as a test server because it’s public and it accepts most types of content.

If you want to dig deeper and learn other cool things you can do with the HttpClient – head on over to the main HttpClient tutorial.

2. Using the AddPart Method

Let’s start by looking at the MultipartEntityBuilder object to add parts to a Http entity which will then be uploaded via a POST operation.

This is a generic method to add parts to an HttpEntity representing the form.

Example 2.1. – Uploading a Form with Two Text Parts and a File

File file = new File(textFileName);
HttpPost post = new HttpPost("http://echo.200please.com");
FileBody fileBody = new FileBody(file, ContentType.DEFAULT_BINARY);
StringBody stringBody1 = new StringBody("Message 1", ContentType.MULTIPART_FORM_DATA);
StringBody stringBody2 = new StringBody("Message 2", ContentType.MULTIPART_FORM_DATA);
// 
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addPart("upfile", fileBody);
builder.addPart("text1", stringBody1);
builder.addPart("text2", stringBody2);
HttpEntity entity = builder.build();
//
post.setEntity(entity);
HttpResponse response = client.execute(post);

Note that we’re instantiating the File object by also specifying the ContentType value to be used by the server.

Also, note that the addPart method has two arguments, acting like key/value pairs for the form. These are only relevant if the server side actually expects and uses parameter names – otherwise, they’re simply ignored.

3. Using the addBinaryBody and addTextBody Methods

A more direct way to create a multipart entity is to use the addBinaryBody and AddTextBody methods. These methods work for uploading text, files, character arrays, and InputStream objects. Let’s illustrate how with simple examples.

Example 3.1. – Uploading Text and a Text File Part

HttpPost post = new HttpPost("http://echo.200please.com");
File file = new File(textFileName);
String message = "This is a multipart post";
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addBinaryBody("upfile", file, ContentType.DEFAULT_BINARY, textFileName);
builder.addTextBody("text", message, ContentType.DEFAULT_BINARY);
// 
HttpEntity entity = builder.build();
post.setEntity(entity);
HttpResponse response = client.execute(post);

Note that the FileBody and StringBody objects are not needed here.

Also important, most servers do not check the ContentType of the text body, so the addTextBody method may omit the ContentType value.

The addBinaryBody API accepts a ContentType – but it is also possible to create the entity just from a binary body and the name of the form parameter holding the file. As stated in the previous section some servers will not recognize the file if the ContentType value is not specified.

Next, we’ll add a zip file as an InputStream, while the image file will be added as File object:

Example 3.2. – Uploading a Zip File, an Image File, and a Text Part

HttpPost post = new HttpPost("http://echo.200please.com");
InputStream inputStream = new FileInputStream(zipFileName);
File file = new File(imageFileName);
String message = "This is a multipart post";
MultipartEntityBuilder builder = MultipartEntityBuilder.create();         
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addBinaryBody
  ("upfile", file, ContentType.DEFAULT_BINARY, imageFileName);
builder.addBinaryBody
  ("upstream", inputStream, ContentType.create("application/zip"), zipFileName);
builder.addTextBody("text", message, ContentType.TEXT_PLAIN);
// 
HttpEntity entity = builder.build();
post.setEntity(entity);
HttpResponse response = client.execute(post);

Note that the ContentType value can be created on the fly, as is the case in the example above for the zip file.

Finally, not all servers acknowledge InputStream parts. The server we instantiated in the first line of the code recognizes InputStreams.

Let’s now look at another example where addBinaryBody is working directly with a byte array:

Example 3.3. – Uploading a Byte Array and Text

HttpPost post = new HttpPost("http://echo.200please.com");
String message = "This is a multipart post";
byte[] bytes = "binary code".getBytes(); 
// 
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addBinaryBody("upfile", bytes, ContentType.DEFAULT_BINARY, textFileName);
builder.addTextBody("text", message, ContentType.TEXT_PLAIN);
// 
HttpEntity entity = builder.build();
post.setEntity(entity);
HttpResponse response = client.execute(post);

Notice the ContentType – which is now specifying binary data.

4. Conclusion

This article has presented the MultipartEntityBuilder as a flexible object which offers multiple API choices to create a multipart form.

The examples have also shown how to use the HttpClient to upload a HttpEntity that similar to a form entity.

The implementation of all these examples and code snippets can be found in our GitHub project – this is an Eclipse based project, so it should be easy to import and run as it is.

I usually post about HTTP stuff on Twitter - you can follow me there:


Sort by:   newest | oldest | most voted
Alex
Guest

So my understanding is always built with MultiPartEntityBuilder and then post. is there a way to stream file from local disk and post directly(without waiting for entire file finish building/loading)? Thanks.

Eugen Paraschiv
Guest

Hey Alex,
While I never tried to do that, I would first experiment with the addBinaryBody API – that takes an InputStream, so you could potentially stream a file from disk. Hope that helps. Cheers,
Eugen.

Amestris
Guest

Thank you for this awesome tutorial. It will help me for the client part of my app. Could you tell me how to get back what we put in “addTextBody” on the server side using HttpServletRequest?

Thank you again.

Eugen Paraschiv
Guest

Glad you found the article useful.
What you add via the addTextBody method, you can then retrieve from the body of the request, on the server side. Usually you don’t need to interact with it manually (for example, if you’re using Spring, you’ll have full support for multipart requests) – but if you do, you can get a Reader out of the request and then read the entire body via that reader. Cheers,
Eugen.

Lydia
Guest

Well thanks alot for this wonderful tutorial, now for my case am dealing with passing Video data from android to the server.I suppose addBinaryBody would work well for that, but my question is, how do i get it back all together at the server side?
Thanks

Eugen Paraschiv
Guest

Hey Lydia – the way you can work with a multipart upload on the server side depends on what framework you’re using there. If – for example – you’re using Spring – you have solid support for that out of the box and it’s pretty easy to use (just do a search for Spring multipart). It’s the framework itself that does the re-assembling of the data stream so you don’t have to do it manually. Of course any mature framework out there will have similar support. Hope that helps. Cheers,
Eugen.

John McAlister
Guest

Can you explain why I would want to do this instead of a PUT or PATCH?

Incidentally – in my application, I am using POST using an InputStream to supply the HTTP payload, with the idea that a stream can be of any length. Is it better to try and break up the binary stream – or am I OK with a single long binary stream for data, letting TCP/IP make sure the data is delivered OK?

Thanks!

Eugen Paraschiv
Guest
Hey John – that’s an interesting question. The way I see it is – when you’re uploading with the HttpClient, you’re not choosing the HTTP verb. You’re adhering to whatever the server asks – since in this case you’re the client. Now – on breaking the content up into parts (or not) – when you’re uploading larger files, it makes sense leveraging the native upload functionality that the browser makes available. You can of course ignore that and simply feed the content into the boxy of your request – but it’s worth looking into the idiomatic way to do upload… Read more »
TheMikester
Guest

Hi John, thanks for putting this article together, it is very useful and easy to digest. One observation though: In section 2, you are adding ContentType to the File object using an API that doesn’t exist. It actually goes on the FileBody object. This is also incorrectly described in the text for the code. Thanks again for a great tutorial!

Eugen Paraschiv
Guest

Nice catch – the content type should have been set on the FileBody, not the File (copy-paste mistake from the actual code).
It’s sorted now – thanks. Cheers,
Eugen.

wpDiscuz