how to resume an interrupted download - part 2

前端 未结 3 1936
别那么骄傲
别那么骄傲 2020-11-28 02:38

This is a continuation of my previous question which I posted when I wasn\'t a registered user. As a refresher, I\'m trying to resume the downloading of a large file from m

相关标签:
3条回答
  • 2020-11-28 02:52

    To resume a download, you need to send not only the Range request header, but also the If-Range request header which should contain either the unique file identifier or the file modification timestamp.

    If the server returns an ETag response header on the initial download, then you should use it in the If-Range header of the subsequent resume requests. Or if it returns a Last-Modified response header, then you should use it in the If-Range request header instead.

    Looking at your logs, the server has sent a Last-Modified response header. So you should send it back along in an If-Range header of the resume request.

    // Initial download.
    String lastModified = connection.getHeaderField("Last-Modified");
    
    // ...
    
    // Resume download.
    connection.setRequestProperty("If-Range", lastModified); 
    

    The server will use this information to verify if you're requesting exactly the same file.

    0 讨论(0)
  • 2020-11-28 02:56

    I managed to implement http resume download on my client Java application, trick was to use "If-Range:original_ETag" request header as mentioned in an accepted answer. Here is a full header debug information it may help you understand how resume works.

    Normal reply from server, file is read from the start to the end. ETag value is W/"filesize_bytes-modified_utc" metadata from the disk file. It could be something else but thats what Tomcat uses and usually is best for regular file content.

    HTTP/1.1 200 OK 
    ETag: W/"19097900-1410863319978" 
    Last-Modified: Tue, 16 Sep 2014 10:28:39 GMT 
    Content-Length: 19097900 
    Content-Type: application/octet-stream 
    Accept-Ranges: bytes 
    Server: Apache-Coyote/1.1 
    Date: Wed, 17 Sep 2014 10:39:52 GMT 
    

    Client reads a given chunk from the file by adding Range and If-Range headers. Byte range can be open so server should read starting from given index to the end. Note Content-Length is not the total length of file but this chunk of bytes.

    Range: bytes=10000000-
    If-Range: W/"19097900-1410863319978"
    
    HTTP/1.1 206 Partial Content 
    ETag: W/"19097900-1410863319978" 
    Last-Modified: Tue, 16 Sep 2014 10:28:39 GMT 
    Content-Length: 9097900 
    Content-Type: application/octet-stream 
    Accept-Ranges: bytes 
    Content-Range: bytes 10000000-19097899/19097900 
    Server: Apache-Coyote/1.1 
    Date: Wed, 17 Sep 2014 18:12:36 GMT 
    

    If remote file was changed then server should not return 206-PartialContent but regular 200-OK reply. Server should use If-Range value to check for consistency. Some clients like VLCPlayer puts Range field without If-Range value.

    When client is making an initial request without Range+If-Range headers it may add "If-Modified-Since: modified_http_date" header. Server may return 304-NotModified status and client is done. If client gives byteStartIdx>=filesize then server returns 416-RequestedRangeNotSatisfiable.

    Additional debug dumps to clarify how http-resume works.

    Range=bytes=0-0
    If-Range=W/"19097900-1410863319978"
    
    HTTP/1.1 206 Partial Content 
    ETag=W/"19097900-1410863319978" 
    Date=Fri, 19 Sep 2014 12:53:36 GMT 
    Content-Length=1 
    Last-Modified=Tue, 16 Sep 2014 10:28:39 GMT 
    Content-Type=application/octet-stream 
    Accept-Ranges=bytes 
    Server=Apache-Coyote/1.1 
    Content-Range=bytes 0-0/19097900 
    - - - - -
    
    Range=bytes=19097800-29097800
    If-Range=W/"19097900-1410863319978"
    
    HTTP/1.1 206 Partial Content 
    ETag=W/"19097900-1410863319978" 
    Date=Fri, 19 Sep 2014 12:59:24 GMT 
    Content-Length=100 
    Last-Modified=Tue, 16 Sep 2014 10:28:39 GMT 
    Content-Type=application/octet-stream 
    Accept-Ranges=bytes 
    Server=Apache-Coyote/1.1 
    Content-Range=bytes 19097800-19097899/19097900 
    - - - - - - - - 
    
    Range=bytes=19097899-19097899
    If-Range=W/"19097900-1410863319978"
    
    HTTP/1.1 206 Partial Content 
    ETag=W/"19097900-1410863319978" 
    Date=Fri, 19 Sep 2014 13:01:47 GMT 
    Content-Length=1 
    Last-Modified=Tue, 16 Sep 2014 10:28:39 GMT 
    Content-Type=application/octet-stream 
    Accept-Ranges=bytes 
    Server=Apache-Coyote/1.1 
    Content-Range=bytes 19097899-19097899/19097900 
    
    0 讨论(0)
  • 2020-11-28 03:07

    Seems that problem is calling

    input = new BufferedInputStream(url.openStream(), 8192);
    

    instead of

    input = new BufferedInputStream(connection.getInputStream(), 8192);
    

    url.openStream() makes another call to openConnection() WITHOUT the range property.

    0 讨论(0)
提交回复
热议问题