Je me suis toujours demandé comment fonctionne les barres de progression d'un téléchargement / téléversement que l'on trouve sur les sites web : comment le code du site web peut-il être au courant de l'avancement d'une telle action puisqu'il est exécuté une fois l'upload terminé ?
Au temps du module PHP pour Apache httpd, je me disais que, vu qu'il s'agit d'un module, il est incrusté au cœur d'Apache httpd donc il doit certainement disposer d'infos supplémentaires. Mais quid des installations dans lesquelles le serveur web est uniquement un reverse proxy vers un serveur d'applications (FastCGI, PHP-FPM, Python uwsgi) ?
La première réponse qui vient à l'esprit est : on surveille la progression de l'upload entièrement côté client avec Ajax.
J'ignorais qu'il est également possible de surveiller l'upload côté serveur. Enfin, pas totalement, puisqu'il faudra toujours de l'Ajax pour actualiser la barre de progression. Mais le reste est fait côté serveur.
A priori, tout le monde s'est mis d'accord sans pour autant produire une norme (en tout cas, le RFC 1867, souvent cité, normalise l'envoi de fichiers avec un formulaire web, mais pas la mesure de la progression d'un upload) :
Quand j'écris « le serveur fait » ceci ou cela, de quel composant précis est-ce que je parle ?
http
du fichier ngnix.conf
, il faut ajouter : upload_progress uploadp 1m;
. On réserve un espace mémoire d'un mégaoctet nommé « uploadp » pour le suivi des uploads ;location
qui envoie les requêtes vers un serveur d'applications, il faut ajouter track_uploads uploadp 30s
. On surveille tous les uploads en les enregistrant dans l'espace mémoire « uploadp » défini ci-dessus. On conserve la trace d'un upload jusqu'à 30 secondes après sa complétion ;Dans le serveur virtuel, on ajoute un nouveau bloc location
capturant l'URL à laquelle l'application est programmée pour venir chercher les informations concernant un upload à coup de XMLHTTPRequest. nginx répondra aux requêtes GET qu'il recevra à cette URL avec les informations concernant un upload dont l'identifiant est passé en argument si celui-ci a été surveillé dans l'espace mémoire « uploadp » :
location ^~ /progressbarupload/upload_progress {
upload_progress_json_output
report_uploads uploadp;
}
sudo systemctl reload nginx
.Notons que le module nginx prend en charge JSONP, JSON with Padding, qui encapsule les données dans un appel de fonction afin de contourner les restrictions inter-domaines : la récupération d'un fichier depuis un autre domaine avec XMLHTTPRequest est interdite par défaut par les navigateurs web sauf si l'on positionne des en-têtes CORS sur le site web sur lequel les données doivent être récupérées, alors que la récupération d'un script JavaScript sans utiliser XMLHTTPRequest est autorisée par défaut. Pour activer un retour au format JSONP, il faut remplacer upload_progress_json_output
par upload_progress_jsonp_output
.
sudo apt-get install libapache2-mod-upload-progress
;location
qui envoie les requêtes vers un serveur d'applications, il faut ajouter TrackUploads On
;Dans le serveur virtuel, on ajoute un nouveau bloc location
capturant à l'URL à laquelle l'application est programmée pour venir chercher les informations concernant un upload à coup de XMLHTTPRequest. nginx répondra aux requêtes GET qu'il recevra à cette URL avec les informations concernant un upload dont l'indentifiant est passé en argument :
<Location ~ '^/progressbarupload/upload_progress'>
ReportUploads On
</Location>
sudo systemctl restart apache2
.Le module Apache httpd prend aussi en charge JSONP. Pour l'activer, il suffit d'ajouter le paramètre callback=<nom_désiré_pour_la_callback>
à la requête HTTP GET qui viendra consulter le rapport d'avancement de l'upload produit par le serveur, il y a rien à activer dans la configuration du serveur web.