Heim  >  Artikel  >  Web-Frontend  >  Implementieren Sie eine segmentierte Download-Funktion basierend auf dem HTTP Range Requests-Protokoll

Implementieren Sie eine segmentierte Download-Funktion basierend auf dem HTTP Range Requests-Protokoll

不言
不言nach vorne
2018-10-17 14:40:546086Durchsuche

In diesem Artikel geht es um die Implementierung segmentierter Downloads basierend auf dem HTTP Range Requests-Protokoll. Ich hoffe, dass er für Sie hilfreich ist.

Dieser Artikel implementiert die segmentierte Download-Funktion basierend auf dem http Range Requests-Protokoll.

Nutzungsszenarien umfassen browserbasierte Streaming-Dateisegmentübertragung, clientbasiertes segmentiertes Herunterladen usw.

Prinzip

http kann über den Header im Zusammenhang mit Bereichsanforderungen mit dem Server verhandeln, um Teilanforderungen zu implementieren.

Der Implementierungsprozess ist unten aufgeführt. Der Code kann in Git eingesehen werden: https://github.com/keller35/partial.

Servercode

Der Server wird mithilfe des Knotens implementiert:

const fs = require('fs');
const path = require('path');
const Koa = require('koa');

const app = new Koa();
const PATH = './resource';

app.use(async ctx => {
    const file = path.join(__dirname, `${PATH}${ctx.path}`);
    // 1、404检查
    try {
        fs.accessSync(file);
    } catch (e) {
        return ctx.response.status = 404;
    }
    const method = ctx.request.method;
    const { size } = fs.statSync(file);
    // 2、响应head请求,返回文件大小
    if ('HEAD' == method) {
        return ctx.set('Content-Length', size);
    }
    const range = ctx.headers['range'];
    // 3、通知浏览器可以进行分部分请求
    if (!range) {
        return ctx.set('Accept-Ranges', 'bytes');
    }
    const { start, end } = getRange(range);
    // 4、检查请求范围
    if (start >= size || end >= size) {
        ctx.response.status = 416;
        return ctx.set('Content-Range', `bytes */${size}`);
    }
    // 5、206分部分响应
    ctx.response.status = 206;
    ctx.set('Accept-Ranges', 'bytes');
    ctx.set('Content-Range', `bytes ${start}-${end ? end : size - 1}/${size}`);
    ctx.body = fs.createReadStream(file, { start, end });
});

app.listen(3000, () => console.log('partial content server start'));

function getRange(range) {
    var match = /bytes=([0-9]*)-([0-9]*)/.exec(range);
    const requestRange = {};
    if (match) {
        if (match[1]) requestRange.start = Number(match[1]);
        if (match[2]) requestRange.end = Number(match[2]);
    }
    return requestRange;
}

Die durch den Code implementierte Funktionslogik ist ungefähr:

  1. Anfrage Überprüfen Sie die Ressource. Wenn sie nicht vorhanden ist, antworten Sie mit 404

  2. Bei HEAD-Anfrage die Ressourcengröße zurückgeben

  3. Bei GET-Anfrage informiert den Bereich nicht, gibt Content -Length zurück, informiert den Browser darüber, dass er fragmentierte Anfragen ausführen kann

  4. Wenn die Anfrage einen Bereich festlegt, prüfen Sie, ob der Bereich zulässig ist und ob dies der Fall ist nicht zulässig, geben Sie einen zulässigen Bereich zurück

  5. Alles ist normal, holen Sie sich den Bereichsteil der Datei und erstellen Sie eine Stream-Antwort

Der Code ist Sehr einfach. Implementieren Sie das Range Requests-Protokoll einfach einmal und es ist in Ordnung. Natürlich gibt es keine vollständige Implementierung des Protokolls, aber das reicht für die Demonstration.

Der Servercode ist in Ordnung. Verwenden Sie eine Browser-Demo, um ihn zu überprüfen.

Browserbeispiele

Moderne Browser implementieren grundsätzlich Range Requests, hier wird der Audio-Tag als Beispiel verwendet.

    
        <title>分片流传输</title>
        <script>
            function jump() {
                const player = document.getElementById(&#39;musicPlayer&#39;);
                // 从30s开始播放
                player.currentTime = 30;
            }
        </script>
    
    
        <audio></audio>
        <button>切到30s</button>
    

Der Endeffekt sieht so aus:

Implementieren Sie eine segmentierte Download-Funktion basierend auf dem HTTP Range Requests-Protokoll

Implementieren Sie eine segmentierte Download-Funktion basierend auf dem HTTP Range Requests-Protokoll

Vergleichen Sie die beiden Bilder Browser Fordern Sie zu diesem Zeitpunkt automatisch Ressourcen an. Dies bedeutet, dass die Ressourcen ab dem 0. Byte geladen werden. Wenn Sie zum Abspielen auf 30 Sekunden klicken, wird der Header zu Range: bytes=0-. Range: bytes=3145728-

Auf ähnliche Weise können Sie mit diesem Servercode auch einen Client implementieren, um an Subunternehmer vergebene Downloads zu simulieren.

Knoten-Unterpaket-Download

Dieses Beispiel zeigt, wie Teile einer Ressource gleichzeitig heruntergeladen und dann in einer Datei zusammengeführt werden.

Dies wird auch mit dem Knoten implementiert:

import request from 'request';
import path from 'path';
import fs from 'fs';

const SINGLE = 1024 * 1000;
const SOURCE = 'http://127.0.0.1:3000/source.mp3';

request({
    method: 'HEAD',
    uri: SOURCE,
}, (err, res) => {
    if (err) return console.error(err);
    const file = path.join(__dirname, './download/source.mp3');
    try {
        fs.closeSync(fs.openSync(file, 'w'));
    } catch (err) {
        return console.error(err);
    }
    const size = Number(res.headers['content-length']);
    const length = parseInt(size / SINGLE);
    for (let i=0; i<length> {
            const range = resp.headers['content-range'];
            const match = /bytes ([0-9]*)-([0-9]*)/.exec(range);
            start = match[1];
            end = match[2];
        }).pipe(fs.createWriteStream(file, {start, end}));
    }
});</length>
Der Code ist relativ einfach. Er besteht darin, mehrere http-Anfragen zu öffnen, Ressourcen gleichzeitig herunterzuladen und dann entsprechend in den entsprechenden Speicherort der Datei zu schreiben der Inhaltsbereich der Antwort.

Das obige ist der detaillierte Inhalt vonImplementieren Sie eine segmentierte Download-Funktion basierend auf dem HTTP Range Requests-Protokoll. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:segmentfault.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen