Implementing Multipart File Uploads with Apache HttpClient in Java
Interfacing with third-party APIs often necessitates transmitting binary data alongside form parameters. When operating with in a Java environment using Apache HttpClient 4.x, constructing a multipart request requires specific handling of entities and connection management. This approach is particularly useful when backend services must proxy file uploads to avoid exposing authentication credentials to client-side applications.
Constructing the HTTP Client Utility
The core logic involves initializing a CloseableHttpClient and configuring timeout parameters to prevent indefinite blocking. A MultipartEntityBuilder is utilized to assemble the request payload, accepting both text and binary parts. Resources must be explicitly managed to prevent connection leaks.
public static String sendMultipartRequest(String endpoint, Map<String, ContentBody> formParts) throws IOException {
CloseableHttpClient httpClientInstance = HttpClients.createDefault();
RequestConfig timeoutConfig = RequestConfig.custom()
.setConnectTimeout(5000)
.setConnectionRequestTimeout(5000)
.setSocketTimeout(15000)
.build();
HttpPost postRequest = new HttpPost(endpoint);
postRequest.setConfig(timeoutConfig);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
for (Map.Entry<String, ContentBody> entry : formParts.entrySet()) {
builder.addPart(entry.getKey(), entry.getValue());
}
postRequest.setEntity(builder.build());
try (CloseableHttpResponse response = httpClientInstance.execute(postRequest)) {
HttpEntity responseEntity = response.getEntity();
if (responseEntity != null) {
return EntityUtils.toString(responseEntity, StandardCharsets.UTF_8);
}
} finally {
httpClientInstance.close();
}
return null;
}
Converting MultipartFile to Standard File
Spring Framework controllers typically receive uploads as MultipartFile objects. However, HttpClient's FileBody requires a standard java.io.File instance. The conversion process involves streaming the content to a temporary location on the disk.
public static File createTempFileFromResource(MultipartFile source) throws IOException {
String originalName = source.getOriginalFilename();
String extension = "";
if (originalName != null && originalName.lastIndexOf(".") > 0) {
extension = originalName.substring(originalName.lastIndexOf("."));
}
File tempFile = File.createTempFile("temp_upload_", extension);
source.transferTo(tempFile);
tempFile.deleteOnExit();
return tempFile;
}
Service Integration Example
Combining these utilities enables a secure upload workflow. Textual metadata is wrapped in StringBody, while the physical file is wrapped in FileBody. This server-side aggregation ensures that API keys and tokens remain cnofidential.
public RestResponse processUploadRequest(MultipartFile document) throws Exception {
Map<String, ContentBody> formParts = new HashMap<>();
formParts.put("application_id", new StringBody("APP_001", ContentType.TEXT_PLAIN));
File localCopy = createTempFileFromResource(document);
formParts.put("document_file", new FileBody(localCopy, ContentType.IMAGE_JPEG));
String responseBody = sendMultipartRequest("https://api.partner.com/upload", formParts);
return RestResponse.success(responseBody);
}