防止 Spring 的 RestTemplate 为 multipart/form-data 中的每个参数添加 header
Prevent Spring's RestTemplate from adding header for each parameters in multipart/form-data
我必须使用 Spring 的 RestTemplate
来调用外部 API,该外部 API 使用 Content-Type: multipart/form-data
请求 POST。输入数据只有 key-values,没有附件,但服务器强制我使用 multipart/form-data
.
以下是运行良好的原始请求。
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 的日志中提取并重新排列的原始请求,它没有工作,因为服务器将 header 误认为值。
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);
问题
如何防止Spring的RestTemplate自动为每个参数header添加Content-Type: text/plain;charset=UTF-8
和Content-Length: xx
如果您认为可以使用 ClientHttpRequestInterceptor 来移除 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);
}
}
并在RestTemplate中这样设置:
RestTemplate restTemplate = new RestTemplate();
List<ClientHttpRequestInterceptor> interceptors = Arrays.asList(new CustomHttpRequestInterceptor())
restTemplate.setInterceptors(interceptors);
我没有找到阻止 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();
}
}
我必须使用 Spring 的 RestTemplate
来调用外部 API,该外部 API 使用 Content-Type: multipart/form-data
请求 POST。输入数据只有 key-values,没有附件,但服务器强制我使用 multipart/form-data
.
以下是运行良好的原始请求。
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 的日志中提取并重新排列的原始请求,它没有工作,因为服务器将 header 误认为值。
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);
问题
如何防止Spring的RestTemplate自动为每个参数header添加Content-Type: text/plain;charset=UTF-8
和Content-Length: xx
如果您认为可以使用 ClientHttpRequestInterceptor 来移除 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);
}
}
并在RestTemplate中这样设置:
RestTemplate restTemplate = new RestTemplate();
List<ClientHttpRequestInterceptor> interceptors = Arrays.asList(new CustomHttpRequestInterceptor())
restTemplate.setInterceptors(interceptors);
我没有找到阻止 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();
}
}