【问题标题】:Spring RestTemplate Large Files ContentLength Auto ChangedSpring RestTemplate 大文件 ContentLength 自动更改
【发布时间】:2016-10-28 19:03:00
【问题描述】:

有一个关于带有大文件的 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("Content-Length", "3764589480"); Content-Length 字段实际上没有被发送,而是标题 Transfer-Encoding: chunked 被发送。

所以我进行了更多测试,结果如下:

硬编码内容长度:Charles 中的结果

“1064589480”:发送内容长度:1064589480

“2064589480”:发送内容长度:2064589480

“3064589480”:删除内容长度,添加传输编码:分块

“3764589480”:删除内容长度,添加传输编码:分块

“4294967295”:删除内容长度,添加传输编码:分块

“4294967296”:发送内容长度:“0”,立即崩溃,写入的字节太多

“4764589480”:发送内容长度:“469622184”

“5764589480”:发送内容长度:“1469622184”

据我推断,在一定数量下,RestTemplate 将从 Content-Length 切换到 Transfer-Encoding。一旦它通过 4294967295,它就开始再次将 Content-Length 传递回 0。 我对此的最佳解决方案是永远不要指定高于 4294967295 的值。如果它高于该阈值,则只需将其设置为 4294967295,RestTemplate 会将其更改为 Transfer-Encoding: 无论如何分块。 是否存在某种溢出/精度点问题?

【问题讨论】:

    标签: java spring resttemplate content-length http-content-length


    【解决方案1】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-24
      • 1970-01-01
      • 1970-01-01
      • 2018-12-06
      • 1970-01-01
      • 2015-03-15
      相关资源
      最近更新 更多