我们将 Spring Boot 从 3.1.11 升级到 3.3.3。升级后,当我们尝试发布 pdf 文件时,我们发现 Rest 模板存在问题。
API 调用突然失败,返回 400 BAD_REQUEST,详细信息如下 直播意外结束
http 调用具有以下标头
Http实体构建如下
headers.set(HttpHeaders.CONTENT_LENGTH, String.valueOf(bytes.length));
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
ByteArrayResource byteArrayResource = new ByteArrayResource(bytes,
"Pdf name") {
@Override
public String getFilename() {
return filename;
}
};
parts.add("data", byteArrayResource);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(parts, headers);
交换是在以下模板的帮助下完成的
exchange(uri, "POST", requestEntity, String.class);
同一段代码在 Spring Boot 3.1.11 上运行良好。这样服务器端的问题就解决了。
我们看到的例外是
at org.springframework.web.client.HttpClientErrorException.create(HttpClientErrorException.java:103) ~[spring-web-6.1.12.jar:6.1.12]
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:183) ~[spring-web-6.1.12.jar:6.1.12]
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:137) ~[spring-web-6.1.12.jar:6.1.12]
at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63) ~[spring-web-6.1.12.jar:6.1.12]
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:942) ~[spring-web-6.1.12.jar:6.1.12]
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:891) ~[spring-web-6.1.12.jar:6.1.12]
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:790) ~[spring-web-6.1.12.jar:6.1.12]
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:672) ~[spring-web-6.1.12.jar:6.1.12]
我们的其余模板实例是按以下方式构建的:
SSLContext sslContext = sslContextBuilder.build();
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("****", "****");
keyManagerFactory.init(clientStore, *****);
sslContext.init(keyManagerFactory.getKeyManagers(), null, ****);
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext);
HttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create().setSSLSocketFactory(socketFactory).build();
CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build();
RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpClient));
为了简洁起见,sslContextBuilder
被排除在外,并出于安全原因屏蔽了一些内容。但配置了tls协议和必要的证书。
Spring 最近似乎一直在研究如何计算内容长度。
我在 3.2.5 版本中遇到了类似的内容长度问题。
尽管内容长度标头似乎具有相同的值,无论是否显式设置,但看起来服务器期望更多数据,并且客户端突然关闭了连接。虽然我仍在进一步调查此行为,但删除显式设置内容长度标头的行解决了该问题:
headers.set(HttpHeaders.CONTENT_LENGTH, String.valueOf(bytes.length));