Java 防止弹簧';通过为多部分/表单数据中的每个参数添加标题来恢复RestTemplate

Java 防止弹簧';通过为多部分/表单数据中的每个参数添加标题来恢复RestTemplate,java,spring,http-headers,multipartform-data,resttemplate,Java,Spring,Http Headers,Multipartform Data,Resttemplate,我必须使用Spring的RestTemplate来调用一个外部API,该API使用内容类型:multipart/form data接收POST请求。输入数据只是键值,没有附件,但服务器强制我使用多部分/表单数据 以下是工作正常的原始请求 POST http://the-api:8080 HTTP/1.1 Content-Type: multipart/form-data; boundary=--Eh0oKOHPOSEIJTzFevDxHhPNKhQl7AP6kQL Accept: */* Hos

我必须使用Spring的
RestTemplate
来调用一个外部API,该API使用
内容类型:multipart/form data
接收POST请求。输入数据只是键值,没有附件,但服务器强制我使用多部分/表单数据

以下是工作正常的原始请求

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--
下面是我从RestTemplate的日志中提取并重新排列的原始请求,它不起作用,因为服务器将头误认为值

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--
下面是代码

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);
HttpHeaders=newhttpheaders();
headers.setContentType(MediaType.MULTIPART\u FORM\u DATA);
多值映射参数=新的LinkedMultiValueMap();
参数添加(“参数1”、“值1”);
参数添加(“参数2”、“值2”);
HttpEntity请求=新的HttpEntity(参数、头);
URI=UriComponentsBuilder.fromHttpUrl(“http://the-api:8080")
.build().encode(Charset.forName(“UTF-8”)).toUri();
返回restemplate.postForObject(uri、请求、KKPMailResponse.class);
问题:
如何防止Spring的RestTemplate自动添加标题
内容类型:text/plain;charset=UTF-8
内容长度:xx
对于每个参数

如果您认为可以使用ClientHttpRequestInterceptor删除标题:

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);
    }
}
并在RestTemplate中按以下方式设置:

RestTemplate restTemplate = new RestTemplate();
List<ClientHttpRequestInterceptor> interceptors = Arrays.asList(new CustomHttpRequestInterceptor())
restTemplate.setInterceptors(interceptors);
RestTemplate RestTemplate=new RestTemplate();
List interceptors=Arrays.asList(新的CustomHttpRequestInterceptor())
restTemplate.setInterceptors(拦截器);

我没有找到阻止Spring生成条目的方法,但是您可以在发送请求之前使用拦截器删除它们。为此,您必须在拦截器中操作请求主体,如下所示:

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

不幸的是,这会删除请求的主标头,而不是每个参数的主体中的标头。另一个问题是头是不可变映射,remove()方法将引发异常。