upload-progress: Módulo de rastreamento de progresso de upload do NGINX
Instalação
Você pode instalar este módulo em qualquer distribuição baseada em RHEL, incluindo, mas não se limitando a:
- RedHat Enterprise Linux 7, 8, 9 e 10
- CentOS 7, 8, 9
- AlmaLinux 8, 9
- Rocky Linux 8, 9
- Amazon Linux 2 e 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
Ative o módulo adicionando o seguinte no início de /etc/nginx/nginx.conf:
load_module modules/ngx_http_uploadprogress_module.so;
Este documento descreve o nginx-module-upload-progress v0.9.4 lançado em 15 de março de 2025.
Introdução
nginx_uploadprogress_module é uma implementação de um sistema de progresso de upload, que monitora uploads POST RFC1867 enquanto são transmitidos para servidores upstream.
Ele funciona rastreando os uploads proxyados pelo NGINX para servidores upstream sem analisar o conteúdo enviado e oferece uma API web para relatar o progresso do upload em Javascript, JSON ou qualquer outro formato (com a ajuda de templates).
Funciona porque o NGINX atua como um acelerador de um servidor upstream, armazenando o conteúdo POST enviado em disco, antes de transmiti-lo para o servidor upstream. Cada solicitação de upload POST individual deve conter um identificador único de progresso.
Este módulo é Copyright (c) 2007-2012 Brice Figureau e está licenciado sob a licença BSD.
- O código rbtree e shm_zone é baseado no módulo limit_zone do NGINX de Igor Sysoev.
- O código do cabeçalho expire é baseado no módulo header_filter do NGINX de Igor Sysoev.
A ideia do JSON e a ideia do mecanismo são baseadas no Lighttpd mod_uploadprogress: http://blog.lighttpd.net/articles/2006/08/01/mod_uploadprogress-is-back
AVISO: quando compilado com --with-debug, este módulo produzirá um grande número de mensagens de log.
Mudanças Incompatíveis
v0.9.0:
JSONP agora é a saída padrão das sondas de progresso. Se você depender deste módulo para servir a saída java obsoleta, use:
upload_progress_java_output
na localização da sonda de progresso.
Configuração
Cada solicitação de upload deve ser atribuída a um identificador único. Este identificador único será usado para armazenar a solicitação e referenciá-la para relatar. Este identificador pode ser transmitido como um argumento GET ou como um cabeçalho HTTP cujo nome é X-Progress-ID.
upload_progress
| Sintaxe | upload_progress <zone_name> <zone_size> |
| Padrão | nenhum |
| Contexto | http |
Esta diretiva habilita o módulo de progresso de upload e reserva <zone_size> bytes para <zone_name>, que será usado para armazenar as informações de rastreamento por conexão.
track_uploads
| Sintaxe | track_uploads <zone_name> <timeout> |
| Padrão | nenhum |
| Contexto | location |
Esta diretiva habilita o rastreamento de uploads para a localização atual. Cada POST que chegar a esta localização registrará a solicitação no rastreador de progresso de upload <zone_name>. Como o NGINX ainda não suporta uploads RFC 1867, a localização deve ser uma localização proxy_pass ou fastcgi. O POST deve ter um parâmetro de consulta chamado X-Progress-ID (ou um cabeçalho HTTP com o mesmo nome) cujo valor é o identificador único usado para obter informações de progresso. Se o POST não tiver essas informações, o upload não será rastreado. As conexões rastreadas são mantidas por no máximo <timeout> segundos após terem sido finalizadas para poder fornecer informações úteis para as sondas de progresso de upload.
AVISO: esta diretiva deve ser a última diretiva da localização. Deve estar em uma localização proxy_pass ou fastcgi_pass.
report_uploads
| Sintaxe | report_uploads <zone_name> |
| Padrão | nenhum |
| Contexto | location |
Esta diretiva permite que uma localização relate o progresso do upload que está sendo rastreado por track_uploads para <zone_name>. O documento retornado é um texto Javascript com os possíveis 4 resultados por padrão:
-
A solicitação de upload ainda não foi registrada ou é desconhecida:
new Object({ 'state' : 'starting' }) -
A solicitação de upload foi finalizada:
new Object({ 'state' : 'done' }) -
A solicitação de upload gerou um erro HTTP:
Um código de erro que pode ser útil para rastrear para o cliente é 413 (entidade da solicitação muito grande).new Object({ 'state' : 'error', 'status' : <error code> }) -
A solicitação de upload está em progresso:
new Object({ 'state' : 'uploading', 'received' : <size_received>, 'size' : <total_size>})
É possível retornar JSON puro em vez deste javascript (veja upload_progress_json_output). Também é possível configurar completamente o formato da resposta com a diretiva upload_progress_template.
A solicitação HTTP para esta localização deve ter um parâmetro X-Progress-ID ou cabeçalho HTTP contendo um identificador único válido de um upload em progresso.
upload_progress_content_type
| Sintaxe | upload_progress_content_type <content_type> |
| Padrão | text/javascript |
| Contexto | location |
Esta diretiva permite alterar o tipo de conteúdo da resposta da sonda de progresso de upload.
upload_progress_header
| Sintaxe | upload_progress_header <progress-id> |
| Padrão | X-Progress-ID |
| Contexto | location |
Esta diretiva permite alterar o nome do cabeçalho do ID de progresso.
upload_progress_jsonp_parameter
| Sintaxe | upload_progress_jsonp_parameter <callback_parameter> |
| Padrão | callback |
| Contexto | location |
Esta diretiva permite alterar o nome do parâmetro GET com o nome do callback jsonp.
upload_progress_java_output
| Sintaxe | upload_progress_java_output |
| Padrão | N/A |
| Contexto | location |
Esta diretiva configura tudo para ser gerado como código javascript compatível com eval().
upload_progress_json_output
| Sintaxe | upload_progress_json_output |
| Padrão | N/A |
| Contexto | location |
Esta diretiva configura tudo para ser gerado como JSON puro.
upload_progress_jsonp_output
| Sintaxe | upload_progress_jsonp_output |
| Padrão | N/A |
| Contexto | location |
Esta diretiva configura tudo para ser gerado como JSONP (como saída JSON, mas com callback).
upload_progress_template
| Sintaxe | upload_progress_template <state> <template> |
| Padrão | nenhum |
| Contexto | location |
Esta diretiva pode ser usada para instalar um template de resposta de progresso. A lista disponível de estados é:
startinguploadingerrordone
O NGINX substituirá o valor das seguintes variáveis por seus respectivos valores para o upload:
$uploadprogress_length: tamanho total do upload$uploadprogress_received: o que o servidor recebeu até agora$uploadprogress_status: código de erro em caso de erro HTTP$uploadprogress_callback: nome do callback jsonp se fornecido como um parâmetro de consulta GET com o nome 'callback'
Por exemplo, para retornar XML (em vez do Javascript ou JSON padrão):
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>';
Exemplo de resposta 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 });";
Exemplo de Configuração
http {
# reserve 1MB sob o nome 'proxied' para rastrear uploads
upload_progress proxied 1m;
server {
listen 127.0.0.1 default;
server_name _ *;
root /path/to/root;
location / {
# proxy para o servidor upstream
proxy_pass http://127.0.0.1;
proxy_redirect default;
# rastrear uploads na zona 'proxied'
# lembrar conexões por 30s após terem terminado
track_uploads proxied 30s;
}
location ^~ /progress {
# relatar uploads rastreados na zona 'proxied'
report_uploads proxied;
}
}
}
Exemplo de Uso
Baseado no exemplo do módulo Lighttpd mod_uploadprogress.
Primeiro, precisamos de um formulário de upload:
<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 Arquivo" />
</form>
E uma barra de progresso para visualizar o progresso:
<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">(progresso)</div>
</div>
Então, precisamos gerar o Identificador Único e iniciar o upload na ação de envio. Isso também iniciará o mecanismo de relatório de progresso ajax.
interval = null;
function openProgressBar() {
/* gerar um progress-id aleatório */
uuid = "";
for (i = 0; i < 32; i++) {
uuid += Math.floor(Math.random() * 16).toString(16);
}
/* atualizar a tag de ação do formulário para incluir o progress-id */
document.getElementById("upload").action="/upload.php?X-Progress-ID=" + uuid;
/* chamar o atualizador de progresso a 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 simples */
var upload = eval(req.responseText);
document.getElementById('tp').innerHTML = upload.state;
/* mudar a largura da barra de progresso interna */
if (upload.state == 'done' || upload.state == 'uploading') {
bar = document.getElementById('progressbar');
w = 400 * upload.received / upload.size;
bar.style.width = w + 'px';
}
/* terminamos, pare o intervalo */
if (upload.state == 'done') {
window.clearTimeout(interval);
}
}
}
}
req.send(null);
}
Software Complementar
Este software também pode funcionar com o Módulo de Upload do NGINX de Valery Kholodkov: http://www.grid.net.ru/nginx/upload.en.html
Você também pode usar as seguintes bibliotecas javascript do lado do cliente: http://drogomir.com/blog/2008/6/30/upload-progress-script-with-safari-support
Observe que ao usar jQuery AJAX para monitoramento de progresso, como: https://github.com/drogus/jquery-upload-progress, você deve ter certeza de definir um parâmetro de template de upload_progress:
upload_progress_json_output
ou
upload_progress_jsonp_output
dependendo da configuração de dataType do seu jQuery AJAX.
GitHub
Você pode encontrar dicas adicionais de configuração e documentação para este módulo no repositório do GitHub para nginx-module-upload-progress.