Below is a form:
<form action="/example/html5/demo_form.asp" method="post"
enctype=”multipart/form-data”>
<input type="file" name="img" />
<input type="text" name=username" value="foo"/>
<input type="submit" />
</form>
when will submit this form, the request will look like this:
POST /example/html5/demo_form.asp HTTP/1.1
Host: 10.143.47.59:9093
Connection: keep-alive
Content-Length: 326
Accept: application/json, text/javascript, */*; q=0.01
Origin: http://10.143.47.59:9093
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryEDKBhMZFowP9Leno
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8,zh-CN;q=0.6,zh;q=0.4
Request Payload
------WebKitFormBoundaryEDKBhMZFowP9Leno
Content-Disposition: form-data; name="username"
foo
------WebKitFormBoundaryEDKBhMZFowP9Leno
Content-Disposition: form-data; name="img"; filename="out.txt"
Content-Type: text/plain
------WebKitFormBoundaryEDKBhMZFowP9Leno--
please pay attention to the "Request Payload", you can see the two params in the form, the username and the img(form-data; name="img"; filename="out.txt"), and the finename is the real file name(or path) in your filesystem, you will receive the file by name(not filename) in your backend(such as spring controller).
if we use Apache Httpclient to simulate the request, we will write such code:
MultipartEntity mutiEntity = newMultipartEntity();
File file = new File("/path/to/your/file");
mutiEntity.addPart("username",new StringBody("foo", Charset.forName("utf-8")));
mutiEntity.addPart("img", newFileBody(file)); //img is name, file is path
But in java 9, We could write such code:
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.
newBuilder(new URI("http:///example/html5/demo_form.asp"))
.method("post",HttpRequest.BodyProcessor.fromString("foo"))
.method("post", HttpRequest.BodyProcessor.fromFile(Paths.get("/path/to/your/file")))
.build();
HttpResponse response = client.send(request, HttpResponse.BodyHandler.asString());
System.out.println(response.body());
Now you see, how could I set the "name" of the param?
A direction in which you can attain making a multiform-data call could be as follows:
BodyProcessor
can be used with their default implementations or else a custom implementation can also be used. Few of the ways to use them are :Read the processor via a string as :
Creating a processor from a file using its path
OR
You can convert the file input to a byte array using the
apache.commons.lang
(or a custom method you can come up with) to add a small util like :and then the byte[] can be used with
BodyProcessor
as:Further, you can create the request as :
The response for the same can be handled as a file and with a new
HttpClient
usingas:
I struggled with this problem for a while, even after seeing and reading this page. But, using the answers on this page to point me in the right direction, reading more about multipart forms and boundaries, and tinkering around, I was able to create a working solution.
The gist of the solution is to use Apache's MultipartEntityBuilder to create the entity and its boundaries (
HttpExceptionBuilder
is a homegrown class):And then a method that uses these helper methods:
It is possible to use
multipart/form-data
or any other content type - but you have to encode the body in the correct format yourself. The client itself does not do any encoding based on the content type.That means your best option is to use another HTTP client the like Apache HttpComponents client or only use the encoder of another library like in the example of @nullpointer's answer.
If you do encode the body yourself, note that you can't call methods like
POST
more than once.POST
simply sets theBodyProcessor
and calling it again will just override any previously set processors. You have to implement one processor that produces the whole body in the correct format.For
multipart/form-data
that means:boundary
header to an appropriate valueEncode each parameter so that it looks like in your example. Basically something like this for text input:
Here, the name refers to the
name
attribute in the HTML form. For the file input in the question, this wouldimg
and the value would be the encoded file content.