I have a REST client calling a REST API.
The REST client uses:
CloseableHttpClient client = HttpClients.createDefault();
URIBuilder builder = new URIBuilder(uri);
HttpPost request = new HttpPost(builder.build().toString());
MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
multipartEntityBuilder.addTextBody("user",username));
multipartEntityBuilder.addTextBody("pass",password));
multipartEntityBuilder.setContentType(ContentType.MULTIPART_FORM_DATA);
multipartEntityBuilder.setCharset(StandardCharsets.UTF_8);
request.setEntity(multipartEntityBuilder.build());
HttpResponse response = client.execute(request);
The REST API endpoint is as follows:
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response authenticateUser(@FormParam("user") String username,
@FormParam("pass") String password) {
try {
String token = authenticate(username, password);
return Response.ok(token).build();
} catch (Exception e) {
return Response.status(Response.Status.FORBIDDEN).build(); }
}
When the API receives the request, the logs show:
Request Headers: {Accept=[application/json], accept-encoding=[gzip,deflate], Authorization=[***], Content-Length=[41], content-type=[application/json], Host=[redacted], Proxy-Authorization=[***], User-Agent=[Apache-HttpClient/4.5.13 (Java/1.8.0_361)], X-Forwarded-For=[redacted], X-Forwarded-Port=[80], X-Forwarded-Proto=[http]}
i.e. the content-type shown is application/json
, not multipart/form-data
. This leads to 415 unsupported media type.
Why would a MultipartEntityBuilder which is using setContentType
of MULTIPART_FORM_DATA
send application/json
? How could I further troubleshoot this and get the API to receive the correct content type in the request?
As an aside, this approach works (from another client calling the same API call), but I want to know why the first one doesn't, as the first one isn't using Spring:
@Autowired
private RestTemplate restTemplate;
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("user", user);
map.add("pass", pass);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, request, String.class);
return response.getBody();
The line multipartEntityBuilder.setContentType(ContentType.MULTIPART_FORM_DATA);
is setting the content type on the multipart form itself, not on the HTTP request. To do what is required, instead the content-type header needs adding to the request itself - as follows:
request.setHeader("Content-Type", "multipart/form-data");