Das Herunterladen von Dateien ist der grundlegendste Dienst, der von WEB-Websites bereitgestellt wird. Aber wissen Sie, wie das fortgesetzte Herunterladen über HTTP implementiert wird?
Hintergrund
In den letzten zwei Tagen habe ich eine Online-Audio- und Videowiedergabe auf Basis von HTML5 implementiert. Da die Datei auf der Unternehmensnetzwerkfestplatte gespeichert ist, ist HTTP nicht erreichbar Zum Lesen und Herunterladen der Datei ist ein Programm erforderlich.Es versteht sich von selbst, dass die Verwendung von Java zum Herunterladen von Dateien lediglich eine Frage des Lesens der Datei und des Schreibens dieser Datei in die Antwort über einen Binärstream ist. Der H5-Player-Anruf kann auch abgespielt werden. Wenn ich jedoch den Fortschritt vorwärts und rückwärts kontrolliere, tritt das Problem auf und es hat überhaupt keine Auswirkung! Wird es trotzdem als Player bezeichnet, wenn es keinen Fast-Forward-Player gibt?
Analyse
Da der Player die zeitliche Länge der Audio- und Videodateien nicht ermitteln kann, ist es zunächst natürlich, an den Inhalt zu denken -Length-Attribut. Im Hintergrund ruft file.length( ) die Dateilänge ab und setzt sie auf Content-Length (der Code lautet wie folgt). Die Länge des Audios und Videos kann im Vordergrund-Player angezeigt werden Wenn ich jedoch zurückspule, ist es immer noch ungültig und es wird im Hintergrund ein Fehler gemeldet.
response.addHeader("Content-Length", file.length());
Ich habe zu Vergleichstests eine HTTP-Datei geändert und festgestellt, dass der direkte HTTP-Zugriff normal vor- und zurückspulen kann. Nach sorgfältiger Analyse der Anforderungs- und Antwortheader der beiden fand ich den Unterschied, die Anforderungsparameter Es gibt weitere Attribute, wie in der folgenden Abbildung dargestellt. Der Name der Attributtabelle muss der vom Server erhaltene Ressourcenbereich sein. Standardmäßig wird durch die Angabe von Schnellvorlauf und Schnellrücklauf der erwartete Startpunkt bestimmt das Range-Attribut.
Dieses Attribut befindet sich jedoch im Anforderungsheader. Woher weiß der Client, dass er dieses Attribut hinzufügen muss? Als ich die Suche fortsetzte, habe ich das Attribut „Accept-Ranges“ gefunden. Der Attributwert ist Bytes und gibt an, ob eine Anfrage zum Abrufen eines Teils einer Entität (z. B. eines Teils einer Datei) akzeptiert werden soll. Bytes: zeigt Akzeptanz an, keine: zeigt keine Akzeptanz an. Dementsprechend gibt es in der Antwort ein weiteres Attribut, Content-Range, das angibt, um welchen Teil des Gesamtobjekts es sich bei dem in der Antwort enthaltenen Teilobjekt handelt. Der vollständige Antwortheader lautet wie folgt:
Lösung
Basierend auf der obigen Analyse wissen wir, wie man auf der Serverseite damit umgeht. Zuerst hinzufügen Akzeptieren Sie den Antwortheader -Ranges.
response.setHeader("Accept-Ranges", "bytes");
Bestimmen Sie dann, ob das Range-Attribut in der Anforderung vorhanden ist, dh ob der angegebene Startpunkt vorhanden ist. Wenn vorhanden, springen Sie über den Sprung des Streams direkt zum Zielstartpunkt und fügen Sie ihn schließlich hinzu Der Name der Content-Range-Attributtabelle bezieht sich auf den Anfangs- und Endpunkt des aktuellen Blocks und lautet wie folgt:
stream = new FileInputStream(file); if(request.getHeader("Range") != null) //客户端请求的下载的文件块的开始字节 { //从请求中得到开始的字节 //请求的格式是: //Range: bytes=[文件块的开始字节]- String range = StringUtils.substringBetween(request.getHeader("Range"), "bytes=", "-"); long start = Long.parseLong(range); //下载的文件(或块)长度 //响应的格式是: //Content-Length: [文件的总大小] - [客户端请求的下载的文件块的开始字节] response.setHeader("Content-Length", String.valueOf(fileSize - start)); if (start != 0) { //要设置状态 //响应的格式是: //HTTP/1.1 206 Partial Content response.setStatus(javax.servlet.http.HttpServletResponse.SC_PARTIAL_CONTENT);//206 //不是从最开始下载, //响应的格式是: //Content-Range: bytes [文件块的开始字节]-[文件的总大小 - 1]/[文件的总大小] response.setHeader("Content-Range","bytes " + start + "-" + String.valueOf(fileSize - 1) + "/" + String.valueOf(fileSize)); stream.skip(start); } } responseBinaryStream(response, this.getContentType(FilenameUtils.getExtension(fileName)), stream);