对大文件的RestTemplate有疑问。是否有最大内容长度和/或它是否会自动更改,尽管明确设置?
我有一个5GB的文件,我想通过HTTP PUT命令发送到我的CDN(Akamai)。我已将其设置如下(以避免java堆空间错误),但是我注意到执行命令时Content-Length会发生变化。
@Autowired
@Qualifier("restTemplateUpload")
public void setRestTemplateUpload(RestTemplate restTemplateUpload)
{
this.restTemplateUpload = restTemplateUpload;
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setBufferRequestBody(false);
restTemplateUpload.setRequestFactory(requestFactory);
}
发送文件的调用:
Resource resource = new FileSystemResource(localFile);
HttpHeaders headers = new HttpHeaders();
Map<String, String> headerValues = new HashMap<String, String>();
headerValues.put("X-Akamai...", value); //There are more headers, but you can assume this is correctly done as I've been able to transmit smaller files
headerValues.put("Host", host);
headers.setAll(headerValues);
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
//I've tried using this and not using this but the result is
//the same, the request sent changes the value to 1469622184
headers.setContentLength(resource.contentLength());
System.out.println(headers.getContentLength()); //Result is: 5764589480
HttpEntity<Resource> uploadRequest = new HttpEntity<Resource>(resource, headers);
response = restTemplateUpload.exchange(hostPath, HttpMethod.PUT, uploadRequest, String.class);
Charles Proxy报告Content-Length 1469622184,当请求达到该长度时,连接将被终止。
Java报告错误:
org.springframework.web.client.ResourceAccessException: I/O error on PUT request for "http://hidden.com/path/largefile.txt": too many bytes written;"
编辑:
当我像这样硬编码Content-Length时,还有一些观察结果:headerValues.put(&#34; Content-Length&#34;,&#34; 3764589480&#34;); Content-Length字段实际上并没有被发送,而是发送了Transfer-Encoding:chunked标题。
所以我运行了更多的测试,这就是发生的事情:
硬编码内容长度:Charles的结果
&#34; 1064589480&#34;:发送内容长度:1064589480
&#34; 2064589480&#34;:发送内容长度:2064589480
&#34; 3064589480&#34;:删除内容长度,添加转移编码:分块
&#34; 3764589480&#34;:删除内容长度,添加转移编码:chunked
&#34; 4294967295&#34;:删除内容长度,添加转移编码:chunked
&#34; 4294967296&#34;:发送内容长度:&#34; 0&#34;,立即崩溃,写入太多字节
&#34; 4764589480&#34;:发送内容长度:&#34; 469622184&#34;
&#34; 5764589480&#34;:发送内容长度:&#34; 1469622184&#34;
据我所知,在一定数量下,RestTemplate将从Content-Length切换到Transfer-Encoding。一旦它通过4294967295,它开始再次将Content-Length传递回0。 我对此的最佳解决方案是永远不要指定高于4294967295的值。如果它高于该阈值,则只需将其设置为4294967295,RestTemplate将其更改为Transfer-Encoding:chunked无论如何。 是否存在某种溢出/精度点问题?
答案 0 :(得分:0)
AFAIK,4294967295字节是您可以在“内容长度”字段中输入的最大数字。即使它超过这个数量,我也建议将它设置为4294967295,因为RestTemplate会自动从使用Content-Length切换到使用Transfer-Encoding:chunked所以无论如何你放大小都无关紧要。
public static final String MAX_TRANSFER_SIZE = "4294967295";
...
HttpHeaders headers = new HttpHeaders();
Map<String, String> headerValues = new HashMap<String, String>();
if (resource.contentLength() > Long.parseLong(MAX_TRANSFER_SIZE))
{
// This is as high as the content length can go. At this size,
// RestTemplate automatically converts from using Content-Length to
// using Transfer-Encoding:chunked.
headerValues.put("Content-Length", MAX_TRANSFER_SIZE);
}
headers.setAll(headerValues);