Heim >Java >javaLernprogramm >Beispiel für die gemeinsame Nutzung der Java-Implementierung des Breakpoint-Resume-Download-Prinzips

Beispiel für die gemeinsame Nutzung der Java-Implementierung des Breakpoint-Resume-Download-Prinzips

黄舟
黄舟Original
2017-09-06 09:54:092032Durchsuche

Anforderungshintergrund

  • Beim Herunterladen dynamisch erstellter Dateien hoffe ich, dass der Browser den Download-Fortschritt anzeigt

  • Dynamisch erstellte Dateien hoffen, dass dies der Fall ist Segmentierter Download

HTTP-Nachricht zur fortsetzbaren Übertragung

Um die HTTPfortsetzbare Übertragung zu implementieren, müssen Sie die folgenden Nachrichten kurz verstehen.

  • Accept-Ranges teilt dem Client (Browser...) mit, dass der Server die Wiederaufnahme von Haltepunkten unterstützt 服务器端返回

  • Range-Client teilt dem Server mit, dass er herunterlädt Ressourcen vom angegebenen Ort/Bereich (hier die Anzahl der Bytes) 客户端发出

  • Content-Range Der Server teilt dem Client die Antwortdateninformationen im gesamten Rückgabetext mit. Die Byteposition dieses Teils 服务器端返回

  • ETag-Ressourcen-ID 非必须 服务器端返回

  • Zuletzt geänderte Ressource, letzte Aktualisierung Das Bereichsformat der Zeit 非必须 服务器端返回

Range

  1. stellt den Bereich von 0-499 Bytes dar: Bereich: Bytes =0-499

  2. stellt den letzten 500-Byte-Bereich dar: Bereich: Bytes=-500

  3. stellt den Bereich vom Anfang bis zum Ende von 500 Byte dar: Bereich : Bytes=500-

  4. stellt das erste und letzte Byte dar: Bereich: Bytes=0-0,-1

  5. Gibt mehrere Bereiche an werden gleichzeitig angegeben: Bereich: Bytes=500-600,601-999

Content-RangeDatenformat

Content-Range: Bytes 0-499/ 22036: Gibt an, dass insgesamt 22036 Byte Datenressourcen im Bereich von 0-499 Byte zurückgegeben werden

Prinzip

  1. Der Client initiiert eine AnforderungseinstellungRangeGibt die an Startanzahl der Bytes oder Es ist nicht erforderlich, die Endbytenummer festzulegen, wenn sie bei 0 beginnt.

  2. Der Server überprüft, ob der Range-Header des Clients die Start-Byte-Nummer und die End-Byte-Nummer analysiert und den Nachrichten-Header Accept-Ranges zurückgibt, der angibt, dass er die Wiederaufnahme des Haltepunkts unterstützt, Content-Range Aufzeichnung Schreiben Sie die Standortinformationen des Streams auf den Client und schreiben Sie dann den Stream auf den Client.

  3. Der Server kann mit ETag Last-Modified markieren, ob die Ressource geändert wurde. Führen Sie einige Überprüfungsarbeiten durch und geben Sie einen Fehler zurück, wenn die Überprüfung fehlschlägt, was nicht erforderlich ist.

Java-Implementierung

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){}
        }
    }
}

Beim Herunterladen von Google Chrome können Sie beispielsweise den Download-Fortschritt sehen, den Download anhalten und den Download-Vorgang fortsetzen, und Sie können auch Einstellungen vornehmen Bereichstestpunkte-Segment herunterladen.


Das obige ist der detaillierte Inhalt vonBeispiel für die gemeinsame Nutzung der Java-Implementierung des Breakpoint-Resume-Download-Prinzips. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn