Implementation of resumable download and resumable download principles
Background
- When downloading a dynamically created file, you want the browser to display the download progress.
- You want to download dynamically created files in multiple parts.
HTTP resumable message
To implementHTTP
For resumable data transfer, you must have a brief understanding of the following packets.
- Accept-Ranges tells the client (Browser...) that the server supports resumable data transfer.
Server return
- The Range client tells the server to download resources from the specified location/Range (the number of bytes here ).
The client sends
- The Content-Range server informs the client of the response data, and the part of the bytes in the whole returned body
Server return
- ETag resource ID
Not Required
Server return
- Last-Modified resource Last Update Time
Not Required
Server return
Range
Range format
Content-Range
Data format
Content-Range: bytes 0-499/22036: indicates that a total of 22036 bytes of data resources are returned in the Range of 0-499 bytes.
Principle
Java Implementation
OutputStream OS = null; InputStream inputStream = null; File zipFile = null; try {long zipStart = System. currentTimeMillis (); zipFile = createFile (); // dynamically create a file if (logger. isInfoEnabled () {logger.info (String. format ("ZIP compression time % s (s)", (System. currentTimeMillis ()-zipStart)/1000);} if (zipFile. exists () {long downloadStart = System. currentTimeMillis (); inputStream = new BufferedInputStream (new FileInputStre Am (zipFile); response. reset (); OS = new BufferedOutputStream (response. getOutputStream (); String userAgent = request. getHeader ("USER-AGENT"); String fileName = zipFile. getName (); if (null! = UserAgent &-1! = UserAgent. indexOf ("MSIE") {fileName = URLEncoder. encode (fileName, "UTF8");} else if (null! = UserAgent &-1! = UserAgent. indexOf ("Mozilla") {fileName = new String (fileName. getBytes ("UTF-8"), "ISO-8859-1");} response. setHeader ("Accept-Ranges", "bytes"); response. setHeader ("Content-Disposition", "attachment; filename =" + fileName); response. setContentType (MediaType. APPLICATION_OCTET_STREAM_VALUE); long pos = 0, fileSize = zipFile. length (), last = fileSize-1; response. setHeader ("ETag", zipFile. getName (). concat (Objects. toString (fileSize )). concat ("_"). concat (Objects. toString (zipFile. lastModified (); response. setDateHeader ("Last-Modified", zipFile. lastModified (); response. setDateHeader ("Expires", System. currentTimeMillis () + 1000*60*60*24); if (null! = Request. getHeader ("Range") {response. setStatus (HttpServletResponse. SC _PARTIAL_CONTENT); try {// currently, only the two range formats are processed. 1. RANGE: bytes = 111-2. Range: bytes = 0-499 String numRang = request. getHeader ("Range "). replaceAll ("bytes =", ""); String [] strRange = numRang. split ("-"); if (strRange. length = 2) {pos = Long. parseLong (strRange [0]. trim (); last = Long. parseLong (strRange [1]. trim ();} else {pos = Long. ParseLong (numRang. replaceAll ("-",""). trim ();} catch (NumberFormatException e) {logger. error (request. getHeader ("Range") + "error"); pos = 0 ;}} long rangLength = last-pos + 1; String contentRange = new StringBuffer ("bytes "). append (String. valueOf (pos )). append ("-"). append (last ). append ("/"). append (String. valueOf (fileSize )). toString (); response. setHeader ("Content-Range", contentRange); r Esponse. addHeader ("Content-Length", Objects. toString (rangLength); if (pos> 0) {inputStream. skip (pos);} byte [] buffer = new byte [1024*512]; // each time you download int length = 0, sendTotal = 0 with MB of traffic; while (sendTotal <rangLength & length! =-1) {length = inputStream. read (buffer, 0, (rangLength-sendTotal) <= buffer. length? (Int) (rangLength-sendTotal): buffer. length); sendTotal = sendTotal + length; OS. write (buffer, 0, length);} if (OS! = Null) {OS. flush ();} if (logger. isInfoEnabled () {logger.info (String. format ("download time % s (s)", (System. currentTimeMillis ()-downloadStart)/1000) ;}} catch (Exception e) {if (StringUtils. endsWithIgnoreCase (e. getMessage (), "Broken pipe") {logger. error ("cancel downloading");} logger. error (e. getMessage (), e);} finally {if (OS! = Null) {try {OS. close ();} catch (Exception e) {}} if (inputStream! = Null) {try {IOUtils. closeQuietly (inputStream);} catch (Exception e ){}}}}
For examplegoogle
You can view the download progress, pause the download, and resume the download in the browser. You can also setRange
Test multipart download.