I have a code that makes a POST request for a specific endpoint. This code is using Apache's HttpClient
and I would like to start using the native HttpClient
from Java (JDK11). But I didn't understand how to specify the parameters of my request.
This is my code using Apache Httpclient:
var path = Path.of("file.txt");
var entity = MultipartEntityBuilder.create()
.addPart("file", new FileBody(path.toFile()))
.addTextBody("token", "<any-token>")
.build();
And the code using HttpClient
:
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
.uri(URI.create("https://myendpoint.com/"))
.POST( /* How can I set the parameters here? */ );
How can I set file
and token
parameters?
We can add parameters using String name-value pairs, or utilize NameValuePairs class for that purpose. Similarly, UriBuilder can be used to add parameters to other HttpClient request methods.
Once created, an HttpClient instance is immutable, thus automatically thread-safe, and you can send multiple requests with it. By default, the client tries to open an HTTP/2 connection. If the server answers with HTTP/1.1, the client automatically falls back to this version.
Unfortunately the Java 11 HTTP client does not provide any convenient support for multipart kind of body. But we can build custom implementation on top of it:
Map<Object, Object> data = new LinkedHashMap<>();
data.put("token", "some-token-value";);
data.put("file", File.createTempFile("temp", "txt").toPath(););
// add extra parameters if needed
// Random 256 length string is used as multipart boundary
String boundary = new BigInteger(256, new Random()).toString();
HttpRequest.newBuilder()
.uri(URI.create("http://example.com"))
.header("Content-Type", "multipart/form-data;boundary=" + boundary)
.POST(ofMimeMultipartData(data, boundary))
.build();
public HttpRequest.BodyPublisher ofMimeMultipartData(Map<Object, Object> data,
String boundary) throws IOException {
// Result request body
List<byte[]> byteArrays = new ArrayList<>();
// Separator with boundary
byte[] separator = ("--" + boundary + "\r\nContent-Disposition: form-data; name=").getBytes(StandardCharsets.UTF_8);
// Iterating over data parts
for (Map.Entry<Object, Object> entry : data.entrySet()) {
// Opening boundary
byteArrays.add(separator);
// If value is type of Path (file) append content type with file name and file binaries, otherwise simply append key=value
if (entry.getValue() instanceof Path) {
var path = (Path) entry.getValue();
String mimeType = Files.probeContentType(path);
byteArrays.add(("\"" + entry.getKey() + "\"; filename=\"" + path.getFileName()
+ "\"\r\nContent-Type: " + mimeType + "\r\n\r\n").getBytes(StandardCharsets.UTF_8));
byteArrays.add(Files.readAllBytes(path));
byteArrays.add("\r\n".getBytes(StandardCharsets.UTF_8));
} else {
byteArrays.add(("\"" + entry.getKey() + "\"\r\n\r\n" + entry.getValue() + "\r\n")
.getBytes(StandardCharsets.UTF_8));
}
}
// Closing boundary
byteArrays.add(("--" + boundary + "--").getBytes(StandardCharsets.UTF_8));
// Serializing as byte array
return HttpRequest.BodyPublishers.ofByteArrays(byteArrays);
}
Here's working example on Github (you need to change VirusTotal API key)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With