Lors du téléchargement de fichiers créés dynamiquement, j'espère que le navigateur affichera la progression du téléchargement
Les fichiers créés dynamiquement espèrent que ils peuvent être segmentés Télécharger
Pour mettre en œuvre la HTTP
transmission avec reprise, vous devez comprendre brièvement les messages suivants.
Accept-Ranges indique au client (navigateur..) que le serveur prend en charge la reprise du point d'arrêt 服务器端返回
Le client Range indique Les téléchargements du serveur ressources de l'emplacement/plage spécifié (le nombre d'octets ici) 客户端发出
Content-Range Le serveur indique au client les informations sur les données de réponse, dans tout le corps du retour La position de l'octet de cette partie 服务器端返回
Identificateur de ressource ETag 非必须
服务器端返回
Dernière mise à jour de la ressource Dernière modification Le format de plage de temps 非必须
服务器端返回
Range
représente la plage de 0 à 499 octets : Plage : octets =0 à 499
représente la plage des 500 derniers octets : Range : bytes=-500
représente la plage du début à la fin des 500 octets : Range : bytes=500-
représente le premier et le dernier octets : Plage : bytes=0-0,-1
Indique que plusieurs plages sont spécifiés en même temps : Plage : octets=500-600,601-999
Content-Range
format de données
Content-Range : octets 0-499/ 22036 : Indique qu'un total de 22 036 octets de ressources de données comprises entre 0 et 499 octets sont renvoyés
Principe
Le client lance un paramètre de requêteRange
Spécifie le nombre d'octets de départ ou Il n'est pas nécessaire de définir le numéro d'octet de fin s'il commence à 0.
Le serveur vérifie que l'en-tête Range
du client analyse le numéro d'octet de début et le numéro d'octet de fin et renvoie l'en-tête du message Accept-Ranges
indiquant qu'il prend en charge la reprise du point d'arrêt, Content-Range
Enregistrement les informations d'emplacement du flux écrit sur le client, puis écrire le flux sur le client.
Le serveur peut utiliser ETag
Last-Modified
pour marquer si la ressource a été modifiée. Effectuez un travail de vérification et renvoyez une erreur si la vérification échoue, ce qui n'est pas obligatoire.
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){} } } }
Par exemple, lors du téléchargement de Google Chrome, vous pouvez voir la progression du téléchargement, suspendre le téléchargement et reprendre les opérations de téléchargement, et vous pouvez également définir Téléchargement du segment des points de test de plage.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!