267. Uploading with multipart

As we saw in the Setting a request body section, we can send a file (text or binary) to the server via BodyPublishers.ofFile() and a POST request.

But sending a classical upload request may involve a multipart form POST with Content-Type as multipart/form-data.

In this case, the request body is made of parts that are delimited by a boundary, as shown in the following illustration (--779d334bbfa... is the boundary):

However, JDK 11's HTTP Client API doesn't provide built-in support for building this kind of request body. Nevertheless, by following the preceding screenshot, we can define a custom BodyPublisher as follows:

public class MultipartBodyPublisher {

private static final String LINE_SEPARATOR = System.lineSeparator();

public static HttpRequest.BodyPublisher ofMultipart(
Map<Object, Object> data, String boundary) throws IOException {

final byte[] separator = ("--" + boundary +
LINE_SEPARATOR + "Content-Disposition: form-data;
name = ").getBytes(StandardCharsets.UTF_8);

final List<byte[] > body = new ArrayList<>();

for (Object dataKey: data.keySet()) {

body.add(separator);
Object dataValue = data.get(dataKey);

if (dataValue instanceof Path) {
Path path = (Path) dataValue;
String mimeType = fetchMimeType(path);

body.add((""" + dataKey + ""; filename="" +
path.getFileName() + """ + LINE_SEPARATOR +
"Content-Type: " + mimeType + LINE_SEPARATOR +
LINE_SEPARATOR).getBytes(StandardCharsets.UTF_8));

body.add(Files.readAllBytes(path));
body.add(LINE_SEPARATOR.getBytes(StandardCharsets.UTF_8));
} else {
body.add((""" + dataKey + """ + LINE_SEPARATOR +
LINE_SEPARATOR + dataValue + LINE_SEPARATOR)
.getBytes(StandardCharsets.UTF_8));
}
}

body.add(("--" + boundary
+ "--").getBytes(StandardCharsets.UTF_8));

return HttpRequest.BodyPublishers.ofByteArrays(body);
}

private static String fetchMimeType(
Path filenamePath) throws IOException {

String mimeType = Files.probeContentType(filenamePath);

if (mimeType == null) {
throw new IOException("Mime type could not be fetched");
}

return mimeType;
}
}

Now, we can create a multipart request, as follows (we try to upload a text file called LoremIpsum.txt to a server that simply sent back the raw form data):

Map<Object, Object> data = new LinkedHashMap<>();
data.put("author", "Lorem Ipsum Generator");
data.put("filefield", Path.of("LoremIpsum.txt"));

String boundary = UUID.randomUUID().toString().replaceAll("-", "");

HttpClient client = HttpClient.newHttpClient();

HttpRequest request = HttpRequest.newBuilder()
.header("Content-Type", "multipart/form-data;boundary=" + boundary)
.POST(MultipartBodyPublisher.ofMultipart(data, boundary))
.uri(URI.create("http://jkorpela.fi/cgi-bin/echoraw.cgi"))
.build();

HttpResponse<String> response = client.send(
request, HttpResponse.BodyHandlers.ofString());

The response should be similar to the following (the boundary is just a random UUID):

--7ea7a8311ada4804ab11d29bcdedcc55
Content-Disposition: form-data; name="author"
Lorem Ipsum Generator
--7ea7a8311ada4804ab11d29bcdedcc55
Content-Disposition: form-data; name="filefield"; filename="LoremIpsum.txt"
Content-Type: text/plain
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
--7ea7a8311ada4804ab11d29bcdedcc55--
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.21.244.217