upload-progress: Módulo de seguimiento del progreso de carga de NGINX
Instalación
Puedes instalar este módulo en cualquier distribución basada en RHEL, incluyendo, pero no limitado a:
- RedHat Enterprise Linux 7, 8, 9 y 10
- CentOS 7, 8, 9
- AlmaLinux 8, 9
- Rocky Linux 8, 9
- Amazon Linux 2 y 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
Habilita el módulo añadiendo lo siguiente en la parte superior de /etc/nginx/nginx.conf:
load_module modules/ngx_http_uploadprogress_module.so;
Este documento describe nginx-module-upload-progress v0.9.4 lanzado el 15 de marzo de 2025.
Introducción
nginx_uploadprogress_module es una implementación de un sistema de progreso de carga que monitorea las cargas POST RFC1867 a medida que se transmiten a servidores upstream.
Funciona rastreando las cargas proxyadas por Nginx a servidores upstream sin analizar el contenido cargado y ofrece una API web para informar el progreso de carga en Javascript, JSON o cualquier otro formato (con la ayuda de plantillas).
Funciona porque Nginx actúa como un acelerador de un servidor upstream, almacenando el contenido POST cargado en disco, antes de transmitirlo al servidor upstream. Cada solicitud de carga POST individual debe contener un identificador único de progreso.
Este módulo es Copyright (c) 2007-2012 Brice Figureau, y está licenciado bajo la licencia BSD.
- El código de rbtree y shm_zone se basa en el módulo limit_zone de Igor Sysoev para Nginx.
- El código del encabezado expire se basa en el módulo header_filter de Igor Sysoev para Nginx.
La idea de JSON y la idea del mecanismo se basan en Lighttpd mod_uploadprogress: http://blog.lighttpd.net/articles/2006/08/01/mod_uploadprogress-is-back
ADVERTENCIA: cuando se compila con --with-debug, este módulo producirá un alto número de mensajes de registro.
Cambios Incompatibles
v0.9.0:
JSONP es ahora la salida predeterminada de las sondas de progreso. Si dependes de este módulo para servir la salida java obsoleta usa:
upload_progress_java_output
en la ubicación de la sonda de progreso.
Configuración
Cada solicitud de carga debe asignarse un identificador único. Este identificador único se utilizará
para almacenar la solicitud y hacer referencia a ella para informar.
Este identificador puede transmitirse ya sea como un argumento GET o como un encabezado HTTP cuyo nombre es X-Progress-ID.
upload_progress
| Sintaxis | upload_progress <zone_name> <zone_size> |
| Predeterminado | ninguno |
| Contexto | http |
Esta directiva habilita el módulo de progreso de carga y reserva <zone_size> bytes para el <zone_name> que
se utilizará para almacenar la información de seguimiento por conexión.
track_uploads
| Sintaxis | track_uploads <zone_name> <timeout> |
| Predeterminado | ninguno |
| Contexto | location |
Esta directiva habilita el seguimiento de cargas para la ubicación actual. Cada POST que llegue a esta ubicación registrará
la solicitud en el rastreador de progreso de carga <zone_name>.
Dado que Nginx aún no soporta la carga RFC 1867, la ubicación debe ser una ubicación proxy_pass o fastcgi.
El POST debe tener un parámetro de consulta llamado X-Progress-ID (o un encabezado HTTP con el mismo nombre) cuyo valor es el
identificador único utilizado para obtener información de progreso. Si el POST no tiene tal información, la carga no será rastreada.
Las conexiones rastreadas se mantienen como máximo <timeout> segundos después de que han terminado para poder servir
información útil a las sondas de progreso de carga.
ADVERTENCIA: esta directiva debe ser la última directiva de la ubicación. Debe estar en una ubicación proxy_pass o
fastcgi_pass.
report_uploads
| Sintaxis | report_uploads <zone_name> |
| Predeterminado | ninguno |
| Contexto | location |
Esta directiva permite a una ubicación informar el progreso de carga que se rastrea mediante track_uploads para <zone_name>.
El documento devuelto es un texto Javascript con los posibles 4 resultados por defecto:
-
La solicitud de carga aún no ha sido registrada o es desconocida:
new Object({ 'state' : 'starting' }) -
La solicitud de carga ha terminado:
new Object({ 'state' : 'done' }) -
La solicitud de carga generó un error HTTP:
Un código de error que puede ser útil para rastrear para el cliente es 413 (entidad de solicitud demasiado grande).new Object({ 'state' : 'error', 'status' : <error code> }) -
La solicitud de carga está en progreso:
new Object({ 'state' : 'uploading', 'received' : <size_received>, 'size' : <total_size>})
Es posible devolver JSON puro en lugar de este javascript (ver upload_progress_json_output).
También es posible configurar completamente el formato de respuesta con la directiva upload_progress_template.
La solicitud HTTP a esta ubicación debe tener un parámetro X-Progress-ID o un encabezado HTTP que contenga un
identificador único válido de una carga en progreso.
upload_progress_content_type
| Sintaxis | upload_progress_content_type <content_type> |
| Predeterminado | text/javascript |
| Contexto | location |
Esta directiva permite cambiar el tipo de contenido de la respuesta de la sonda de progreso de carga.
upload_progress_header
| Sintaxis | upload_progress_header <progress-id> |
| Predeterminado | X-Progress-ID |
| Contexto | location |
Esta directiva permite cambiar el nombre del encabezado del ID de progreso.
upload_progress_jsonp_parameter
| Sintaxis | upload_progress_jsonp_parameter <callback_parameter> |
| Predeterminado | callback |
| Contexto | location |
Esta directiva permite cambiar el nombre del parámetro GET con el nombre de la función de devolución de llamada jsonp.
upload_progress_java_output
| Sintaxis | upload_progress_java_output |
| Predeterminado | N/A |
| Contexto | location |
Esta directiva establece todo para que se produzca como código javascript compatible con eval().
upload_progress_json_output
| Sintaxis | upload_progress_json_output |
| Predeterminado | N/A |
| Contexto | location |
Esta directiva establece todo para que se produzca como JSON puro.
upload_progress_jsonp_output
| Sintaxis | upload_progress_jsonp_output |
| Predeterminado | N/A |
| Contexto | location |
Esta directiva establece todo para que se produzca como JSONP (como salida JSON, pero con devolución de llamada).
upload_progress_template
| Sintaxis | upload_progress_template <state> <template> |
| Predeterminado | ninguno |
| Contexto | location |
Esta directiva se puede utilizar para instalar una plantilla de respuesta de progreso. La lista disponible de estados es:
startinguploadingerrordone
Nginx reemplazará el valor de las siguientes variables con su respectivo valor para la carga:
$uploadprogress_length: tamaño total de la carga$uploadprogress_received: lo que el servidor ha recibido hasta ahora$uploadprogress_status: código de error en caso de error HTTP$uploadprogress_callback: nombre de la devolución de llamada jsonp si se proporciona como un parámetro de consulta GET con el nombre 'callback'
Por ejemplo, para devolver XML (en lugar del Javascript o JSON predeterminado):
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>';
Ejemplo de respuesta 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 });";
Ejemplo de Configuración
http {
# reservar 1MB bajo el nombre 'proxied' para rastrear cargas
upload_progress proxied 1m;
server {
listen 127.0.0.1 default;
server_name _ *;
root /path/to/root;
location / {
# proxy a servidor upstream
proxy_pass http://127.0.0.1;
proxy_redirect default;
# rastrear cargas en la zona 'proxied'
# recordar conexiones durante 30s después de que terminen
track_uploads proxied 30s;
}
location ^~ /progress {
# informar cargas rastreadas en la zona 'proxied'
report_uploads proxied;
}
}
}
Ejemplo de Uso
Basado en el ejemplo del módulo Lighttpd mod_uploadprogress.
Primero necesitamos un formulario de carga:
<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="Enviar Archivo" />
</form>
Y una barra de progreso para visualizar el progreso:
<div>
<div id="progress" style="width: 400px; border: 1px solid black">
<div id="progressbar"
style="width: 1px; background-color: black; border: 1px solid white">
</div>
</div>
<div id="tp">(progreso)</div>
</div>
Luego necesitamos generar el Identificador Único y lanzar la carga en la acción de envío. Esto también iniciará el mecanismo de informe de progreso ajax.
interval = null;
function openProgressBar() {
/* generar un progress-id aleatorio */
uuid = "";
for (i = 0; i < 32; i++) {
uuid += Math.floor(Math.random() * 16).toString(16);
}
/* parchear la etiqueta de acción del formulario para incluir el progress-id */
document.getElementById("upload").action="/upload.php?X-Progress-ID=" + uuid;
/* llamar al actualizador de progreso cada 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 de pobre */
var upload = eval(req.responseText);
document.getElementById('tp').innerHTML = upload.state;
/* cambiar el ancho de la barra de progreso interna */
if (upload.state == 'done' || upload.state == 'uploading') {
bar = document.getElementById('progressbar');
w = 400 * upload.received / upload.size;
bar.style.width = w + 'px';
}
/* hemos terminado, detener el intervalo */
if (upload.state == 'done') {
window.clearTimeout(interval);
}
}
}
}
req.send(null);
}
Software Complementario
Este software también puede funcionar con el Módulo de Carga de Nginx de Valery Kholodkov: http://www.grid.net.ru/nginx/upload.en.html
También puedes usar las siguientes bibliotecas de javascript del lado del cliente: http://drogomir.com/blog/2008/6/30/upload-progress-script-with-safari-support
Ten en cuenta que al usar jQuery AJAX para el monitoreo de progreso, como: https://github.com/drogus/jquery-upload-progress debes asegurarte de establecer un parámetro de plantilla upload_progress:
upload_progress_json_output
o
upload_progress_jsonp_output
dependiendo de tu configuración de dataType de jQuery AJAX.
GitHub
Puedes encontrar consejos de configuración adicionales y documentación para este módulo en el repositorio de GitHub para nginx-module-upload-progress.