Aller au contenu

upload-progress: Module de suivi de progression de téléchargement NGINX

Installation

Vous pouvez installer ce module dans toute distribution basée sur RHEL, y compris, mais sans s'y limiter :

  • RedHat Enterprise Linux 7, 8, 9 et 10
  • CentOS 7, 8, 9
  • AlmaLinux 8, 9
  • Rocky Linux 8, 9
  • Amazon Linux 2 et Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-upload-progress
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-upload-progress

Activez le module en ajoutant ce qui suit en haut de /etc/nginx/nginx.conf :

load_module modules/ngx_http_uploadprogress_module.so;

Ce document décrit nginx-module-upload-progress v0.9.4 publié le 15 mars 2025.


Introduction

nginx_uploadprogress_module est une implémentation d'un système de suivi de progression de téléchargement, qui surveille les téléchargements POST RFC1867 pendant qu'ils sont transmis aux serveurs en amont.

Il fonctionne en suivant les téléchargements proxyés par Nginx vers les serveurs en amont sans analyser le contenu téléchargé et offre une API web pour signaler la progression du téléchargement en Javascript, JSON ou tout autre format (avec l'aide de modèles).

Il fonctionne parce que Nginx agit comme un accélérateur d'un serveur en amont, stockant le contenu POST téléchargé sur disque, avant de le transmettre au serveur en amont. Chaque requête de téléchargement POST individuelle devrait contenir un identifiant unique de progression.

Ce module est Copyright (c) 2007-2012 Brice Figureau, et est sous licence BSD.

  • Le code rbtree et shm_zone est basé sur le module Nginx limit_zone d'Igor Sysoev.
  • Le code d'en-tête expire est basé sur le module Nginx header_filter d'Igor Sysoev.

L'idée JSON et le mécanisme sont basés sur Lighttpd mod_uploadprogress : http://blog.lighttpd.net/articles/2006/08/01/mod_uploadprogress-is-back

AVERTISSEMENT : lorsqu'il est compilé avec --with-debug, ce module produira un grand nombre de messages de journal.

Changements incompatibles

v0.9.0 :

JSONP est maintenant la sortie par défaut des sondes de progression. Si vous dépendez de ce module pour servir la sortie java obsolète, utilisez :

upload_progress_java_output

dans l'emplacement de la sonde de progression.

Configuration

Chaque requête de téléchargement doit se voir attribuer un identifiant unique. Cet identifiant unique sera utilisé pour stocker la requête et la référencer pour rapporter. Cet identifiant peut être transmis soit comme un argument GET soit comme un en-tête HTTP dont le nom est X-Progress-ID.

upload_progress

Syntaxe upload_progress <zone_name> <zone_size>
Par défaut aucun
Contexte http

Cette directive active le module de progression de téléchargement et réserve <zone_size> octets pour <zone_name> qui sera utilisé pour stocker les informations de suivi par connexion.

track_uploads

Syntaxe track_uploads <zone_name> <timeout>
Par défaut aucun
Contexte location

Cette directive active le suivi des téléchargements pour l'emplacement actuel. Chaque POST arrivant dans cet emplacement enregistrera la requête dans le traqueur de progression de téléchargement <zone_name>. Puisque Nginx ne prend pas encore en charge le téléchargement RFC 1867, l'emplacement doit être un emplacement proxy_pass ou fastcgi. Le POST doit avoir un paramètre de requête appelé X-Progress-ID (ou un en-tête HTTP du même nom) dont la valeur est l' identifiant unique utilisé pour obtenir des informations de progression. Si le POST ne contient pas de telles informations, le téléchargement ne sera pas suivi. Les connexions suivies sont conservées au maximum <timeout> secondes après leur achèvement pour pouvoir fournir des informations utiles aux sondes de progression de téléchargement.

AVERTISSEMENT : cette directive doit être la dernière directive de l'emplacement. Elle doit être dans un emplacement proxy_pass ou fastcgi_pass.

report_uploads

Syntaxe report_uploads <zone_name>
Par défaut aucun
Contexte location

Cette directive permet à un emplacement de signaler la progression du téléchargement qui est suivie par track_uploads pour <zone_name>. Le document retourné est un texte Javascript avec les 4 résultats possibles par défaut :

  • La requête de téléchargement n'a pas encore été enregistrée ou est inconnue :

    new Object({ 'state' : 'starting' })
    

  • La requête de téléchargement est terminée :

    new Object({ 'state' : 'done' })
    

  • La requête de téléchargement a généré une erreur HTTP :

    new Object({ 'state' : 'error', 'status' : <error code> })
    
    Un code d'erreur qui peut être utile pour le suivi côté client est 413 (entité de requête trop grande).

  • La requête de téléchargement est en cours :

    new Object({ 'state' : 'uploading', 'received' : <size_received>, 'size' : <total_size>})
    

Il est possible de retourner du JSON pur au lieu de ce javascript (voir upload_progress_json_output). Il est également possible de configurer complètement le format de réponse avec la directive upload_progress_template.

La requête HTTP vers cet emplacement doit avoir un paramètre X-Progress-ID ou un en-tête HTTP contenant un identifiant unique valide d'un téléchargement en cours.

upload_progress_content_type

Syntaxe upload_progress_content_type <content_type>
Par défaut text/javascript
Contexte location

Cette directive permet de changer le type de contenu de la réponse de la sonde de progression de téléchargement.

upload_progress_header

Syntaxe upload_progress_header <progress-id>
Par défaut X-Progress-ID
Contexte location

Cette directive permet de changer le nom de l'en-tête de l'identifiant de progression.

upload_progress_jsonp_parameter

Syntaxe upload_progress_jsonp_parameter <callback_parameter>
Par défaut callback
Contexte location

Cette directive permet de changer le nom du paramètre GET avec le nom de la fonction de rappel jsonp.

upload_progress_java_output

Syntaxe upload_progress_java_output
Par défaut N/A
Contexte location

Cette directive définit tout pour être sorti comme du code javascript compatible avec eval().

upload_progress_json_output

Syntaxe upload_progress_json_output
Par défaut N/A
Contexte location

Cette directive définit tout pour être sorti comme du JSON pur.

upload_progress_jsonp_output

Syntaxe upload_progress_jsonp_output
Par défaut N/A
Contexte location

Cette directive définit tout pour être sorti comme JSONP (comme la sortie JSON, mais avec un rappel).

upload_progress_template

Syntaxe upload_progress_template <state> <template>
Par défaut aucun
Contexte location

Cette directive peut être utilisée pour installer un modèle de réponse de progression. La liste des états disponibles est :

  • starting
  • uploading
  • error
  • done

Nginx remplacera la valeur des variables suivantes par leur valeur respective pour le téléchargement :

  • $uploadprogress_length : taille totale du téléchargement
  • $uploadprogress_received : ce que le serveur a reçu jusqu'à présent
  • $uploadprogress_status : code d'erreur en cas d'erreur HTTP
  • $uploadprogress_callback : nom de la fonction de rappel jsonp si fourni comme paramètre de requête GET avec le nom 'callback'

Par exemple, pour retourner du XML (au lieu du Javascript ou JSON par défaut) :

upload_progress_content_type 'text/xml';
upload_progress_template starting '<upload><state>starting</state></upload>';
upload_progress_template uploading '<upload><state>uploading</state><size>$uploadprogress_length</size><uploaded>$uploadprogress_received</uploaded></upload>';
upload_progress_template done '<upload><state>done</state></upload>';
upload_progress_template error '<upload><state>error</state><code>$uploadprogress_status</code></upload>';

Exemple de réponse JSONP :

upload_progress_template starting "$uploadprogress_callback({ \"state\" : \"starting\"});";
upload_progress_template error "$uploadprogress_callback({ \"state\" : \"error\", \"status\" : $uploadprogress_status });";
upload_progress_template done "$uploadprogress_callback({ \"state\" : \"done\"});";
upload_progress_template uploading "$uploadprogress_callback({ \"state\" : \"uploading\", \"received\" : $uploadprogress_received, \"size\" : $uploadprogress_length });";

Exemple de configuration

http {
    # réserve 1 Mo sous le nom 'proxied' pour suivre les téléchargements
    upload_progress proxied 1m;

    server {
        listen       127.0.0.1 default;
        server_name  _ *;

        root /path/to/root;

        location / {
            # proxy vers le serveur en amont
            proxy_pass http://127.0.0.1;
            proxy_redirect default;

            # suivre les téléchargements dans la zone 'proxied'
            # se souvenir des connexions pendant 30s après leur achèvement
            track_uploads proxied 30s;
        }

        location ^~ /progress {
            # rapporter les téléchargements suivis dans la zone 'proxied'
            report_uploads proxied;
        }
    }
}

Exemple d'utilisation

Basé sur l'exemple du module Lighttpd mod_uploadprogress.

Tout d'abord, nous avons besoin d'un formulaire de téléchargement :

<form id="upload" enctype="multipart/form-data"
  action="/upload.php" method="post"
  onsubmit="openProgressBar(); return true;">
  <input type="hidden" name="MAX_FILE_SIZE" value="30000000"  />
  <input name="userfile" type="file" label="fileupload" />
  <input type="submit" value="Envoyer le fichier" />
</form>

Et une barre de progression pour visualiser la progression :

<div>
  <div id="progress" style="width: 400px; border: 1px solid black">
    <div id="progressbar"
      style="width: 1px; background-color: black; border: 1px solid white">
      &nbsp;
    </div>
  </div>
  <div id="tp">(progression)</div>
</div>

Ensuite, nous devons générer l'identifiant unique et lancer le téléchargement lors de l'action de soumission. Cela démarrera également le mécanisme de rapport de progression ajax.

interval = null;

function openProgressBar() {
  /* générer un identifiant de progression aléatoire */
  uuid = "";
  for (i = 0; i < 32; i++) {
    uuid += Math.floor(Math.random() * 16).toString(16);
  }
  /* patcher la balise action du formulaire pour inclure l'identifiant de progression */
  document.getElementById("upload").action="/upload.php?X-Progress-ID=" + uuid;

  /* appeler le mise à jour de progression toutes les 1000ms */
  interval = window.setInterval(
    function () {
      fetch(uuid);
    },
    1000
  );
}

function fetch(uuid) {
  req = new XMLHttpRequest();
  req.open("GET", "/progress", 1);
  req.setRequestHeader("X-Progress-ID", uuid);
  req.onreadystatechange = function () {
    if (req.readyState == 4) {
      if (req.status == 200) {
        /* parser JSON basique */
        var upload = eval(req.responseText);

        document.getElementById('tp').innerHTML = upload.state;

        /* changer la largeur de la barre de progression intérieure */
        if (upload.state == 'done' || upload.state == 'uploading') {
          bar = document.getElementById('progressbar');
          w = 400 * upload.received / upload.size;
          bar.style.width = w + 'px';
        }
        /* nous avons terminé, arrêter l'intervalle */
        if (upload.state == 'done') {
          window.clearTimeout(interval);
        }
      }
    }
  }
  req.send(null);
}

Logiciel compagnon

Ce logiciel peut également fonctionner avec le module de téléchargement Nginx de Valery Kholodkov : http://www.grid.net.ru/nginx/upload.en.html

Vous pouvez également utiliser les bibliothèques javascript suivantes côté client : http://drogomir.com/blog/2008/6/30/upload-progress-script-with-safari-support

Notez que lors de l'utilisation de jQuery AJAX pour le suivi de progression, tel que : https://github.com/drogus/jquery-upload-progress vous devez vous assurer de définir un paramètre de modèle upload_progress :

upload_progress_json_output

ou

upload_progress_jsonp_output

selon votre paramètre dataType jQuery AJAX.

GitHub

Vous pouvez trouver des conseils de configuration supplémentaires et de la documentation pour ce module dans le dépôt GitHub pour nginx-module-upload-progress.