When downloading dynamically created files, I hope the browser will display the download progress
I hope the dynamically created files can be segmented Download
To implement HTTP
resumable transmission, you must briefly understand the following messages.
Accept-Ranges tells the client (browser..) that the server supports breakpoint resumption The server returns
Range The client tells the server to download resources from the specified location/range (number of bytes here) The client issues
Content-Range server Tell the client the response data information, the byte position of this part in the entire return body The server returns
ETag resource identifier Not required
Server-side return
Last-Modified resource last updated time Not required
Server-side return
## The range format of
#Range
Content-Range data format
RangeSpecify the start The number of bytes or the number of end bytes does not need to be set if it starts from 0.
Range header parses the starting byte number and ending byte number and returns the message header
Accept-Ranges Indicates that breakpoint resumption is supported,
Content-Range records the location information of the stream written to the client, and then writes the stream to the client.
ETag
Last-Modified to mark whether the resource has been modified. Do some verification work, and return an error if the verification fails, which is not required.
OutputStream os=null; InputStream inputStream =null; File zipFile=null; try{ long zipStart=System.currentTimeMillis(); zipFile=createFile();//动态根据业务创建文件 if(logger.isInfoEnabled()){ logger.info(String.format("压缩ZIP 花费时间 %s(s) ", (System.currentTimeMillis()-zipStart)/1000)); } if (zipFile.exists()) { long downloadStart=System.currentTimeMillis(); inputStream= new BufferedInputStream(new FileInputStream(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 { // 暂时只处理这2种range格式 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); response.addHeader("Content-Length",Objects.toString(rangLength)); if(pos>0){ inputStream.skip(pos); } byte[] buffer = new byte[1024*512];//每次以512KB 0.5MB的流量下载 int length = 0,sendTotal=0; 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("下载 花费时间 %s(s) ", (System.currentTimeMillis()-downloadStart)/1000)); } } }catch (Exception e){ if(StringUtils.endsWithIgnoreCase(e.getMessage(),"Broken pipe")){ logger.error("用户取消下载"); } 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){} } } }
The above is the detailed content of Example sharing of Java implementation of breakpoint resume download principle. For more information, please follow other related articles on the PHP Chinese website!