asinkxcoswt
asinkxcoswt

Reputation: 2544

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

Upvotes: 3

Views: 3267

Answers (2)

Malte Finsterwalder
Malte Finsterwalder

Reputation: 134

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();
    }
}

Upvotes: 2

Kamil W
Kamil W

Reputation: 2366

If think you can use ClientHttpRequestInterceptor to remove headers:

public class SomeHttpRequestInterceptor implements ClientHttpRequestInterceptor
{

   @Override
   public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException
   {
        HttpHeaders headers = request.getHeaders();
        headers.remove("your header 1);
        headers.remove("your header 2);
        return execution.execute(request, body);
    }
}

And set it in RestTemplate in this way:

RestTemplate restTemplate = new RestTemplate();
List<ClientHttpRequestInterceptor> interceptors = Arrays.asList(new CustomHttpRequestInterceptor())
restTemplate.setInterceptors(interceptors);

Upvotes: 1

Related Questions