Maison  >  Article  >  interface Web  >  Implémenter une fonction de téléchargement segmenté basée sur le protocole http Range Requests

Implémenter une fonction de téléchargement segmenté basée sur le protocole http Range Requests

不言
不言avant
2018-10-17 14:40:546086parcourir

Ce que cet article vous apporte concerne la fonction de mise en œuvre de téléchargements segmentés basés sur le protocole http Range Requests. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

Cet article implémente la fonction de téléchargement segmenté basée sur le protocole http Range Requests.

Les scénarios d'utilisation incluent la transmission de segments de fichiers en streaming basée sur un navigateur, le téléchargement segmenté basé sur le client, etc.

Principe

http peut négocier avec le serveur via l'en-tête lié aux requêtes de plage pour implémenter des requêtes partielles.

Le processus d'implémentation est publié ci-dessous. Le code peut être consulté dans git : https://github.com/keller35/partial.

Code du serveur

Le serveur est implémenté à l'aide du nœud :

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;
}

La logique fonctionnelle implémentée par le code est grossièrement :

  1. Vérifiez la ressource demandée. Si elle n'existe pas, répondez par 404

  2. Pour la requête HEAD, renvoyez la taille de la ressource

  3. Si la ressource est demandée. La requête GET n'informe pas la plage, renvoie Content-Length pour informer le navigateur qu'il peut effectuer des requêtes fragmentées

  4. Si la requête définit une plage, vérifiez si la plage est légale. n'est pas légal, renvoie une plage légale

  5. Tout est normal, récupère la partie plage du fichier et fais une réponse en flux

Le code est très simple, il suffit d'implémenter le protocole Range Requests une fois et tout ira bien. Bien sûr, le protocole n'est pas entièrement implémenté ici, mais cela suffit pour la démonstration ici.

Le code du serveur est OK, utilisez une démo du navigateur pour le vérifier.

Exemples de navigateurs

Les navigateurs modernes implémentent essentiellement les requêtes de plage, ici la balise audio est utilisée comme exemple.

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

L'effet final est le suivant :

Implémenter une fonction de téléchargement segmenté basée sur le protocole http Range Requests

Implémenter une fonction de téléchargement segmenté basée sur le protocole http Range Requests

Comparez les deux images. , Le navigateur demande automatiquement des ressources. A ce moment, l'en-tête a Range: bytes=0-, ce qui signifie que la ressource sera chargée à partir du 0ème octet ; lorsque le clic passe à 30 secondes pour jouer, l'en-tête devient Range: bytes=3145728-.

De la même manière, en utilisant ce code serveur, vous pouvez également implémenter un client pour simuler des téléchargements sous-traités.

Téléchargement du sous-package de nœud

Cet exemple montre comment télécharger simultanément des parties d'une ressource, puis la fusionner en un seul fichier.

Ceci est également implémenté à l'aide de node :

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>

Le code est relativement simple, il s'agit d'ouvrir plusieurs requêtes http, de télécharger des ressources simultanément, puis d'écrire le fichier correspondant en fonction du contenu -portée de la réponse.

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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer