Search code examples
javaspringhttp-headersmultipartform-dataresttemplate

Prevent Spring's RestTemplate from adding header for each parameters in multipart/form-data


I have to use Spring's RestTemplate to call an external API that takes a POST request with Content-Type: multipart/form-data. The input data are only key-values, no attachments but the server enforce me the use multipart/form-data.

Following is the raw request that works fine.

POST http://the-api:8080 HTTP/1.1
Content-Type: multipart/form-data; boundary=--Eh0oKOHPOSEIJTzFevDxHhPNKhQl7AP6kQL
Accept: */*
Host: the-api:8080
accept-encoding: gzip, deflate
content-length: 680
Connection: keep-alive

--Eh0oKOHPOSEIJTzFevDxHhPNKhQl7AP6kQL
Content-Disposition: form-data; name="param1"

value1
--Eh0oKOHPOSEIJTzFevDxHhPNKhQl7AP6kQL
Content-Disposition: form-data; name="param2"

value2
--Eh0oKOHPOSEIJTzFevDxHhPNKhQl7AP6kQL--

Following is the raw request that I extracted and rearranged from the log of the RestTemplate, it did not work because the server mistook the header for the value.

POST http://the-api:8080 HTTP/1.1
Content-Type: multipart/form-data; boundary=--Eh0oKOHPOSEIJTzFevDxHhPNKhQl7AP6kQL
Accept: */*
Host: the-api:8080
accept-encoding: gzip, deflate
content-length: 680
Connection: keep-alive

--Eh0oKOHPOSEIJTzFevDxHhPNKhQl7AP6kQL
Content-Disposition: form-data; name="param1"
Content-Type: text/plain;charset=UTF-8
Content-Length: 29

value1
--Eh0oKOHPOSEIJTzFevDxHhPNKhQl7AP6kQL
Content-Disposition: form-data; name="param2"
Content-Type: text/plain;charset=UTF-8
Content-Length: 14

value2
--Eh0oKOHPOSEIJTzFevDxHhPNKhQl7AP6kQL--

Following is the code

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("param1", "value1);
params.add("param2", "value2);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);

URI uri = UriComponentsBuilder.fromHttpUrl("http://the-api:8080")
        .build().encode(Charset.forName("UTF-8")).toUri();

return restTemplate.postForObject(uri, request, KKPMailResponse.class);

Question

How to prevent Spring's RestTemplate from automatically add the header Content-Type: text/plain;charset=UTF-8 and Content-Length: xx for each parameters


Solution

  • I didn't find a way to prevent Spring from generating the entries, but you can use an interceptor to remove them before sending the request. For that you have to manipulate the request body in the interceptor as follows:

    public class MultiPartFormDataCleaningInterceptor implements ClientHttpRequestInterceptor {
    
        @Override
        public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
            final MediaType contentType = request.getHeaders().getContentType();
            if (contentType != null
                    && MediaType.MULTIPART_FORM_DATA.getType().equals(contentType.getType())
                    && MediaType.MULTIPART_FORM_DATA.getSubtype().equals(contentType.getSubtype())) {
                return execution.execute(request, stripContentTypeAndLength(body));
            }
            return execution.execute(request, body);
        }
    
        private byte[] stripContentTypeAndLength(byte[] body) {
            final String bodyStr = new String(body);
            final StringBuilder builder = new StringBuilder();
            try (final Scanner scanner = new Scanner(bodyStr)) {
                while (scanner.hasNextLine()) {
                    final String line = scanner.nextLine();
                    if (!line.startsWith("Content-Type:")
                            && !line.startsWith("Content-Length:")) {
                        builder.append(line).append("\r\n");
                    }
                }
            }
            final String newBodyStr = builder.toString();
            return newBodyStr.getBytes();
        }
    }