Envie uma única resposta bem-sucedida, escreva o corpo progressivamente e finalize a mensagem normalmente. Este passo a passo no Terminal do Mac mostra como entregar um documento sintético completo sem tratar cada parte como uma resposta separada nem usar 206 Partial Content.
A tarefa consiste em disponibilizar uma página HTML destinada à hospedagem pública e, em seguida, verificar se o cliente recebe todo o conteúdo. A demonstração é executada localmente e não publica nada. Você precisa do Terminal, do curl e de uma versão LTS compatível do Node.js, disponível na página oficial de download do Node.js.
Por que partes não significam respostas parciais
O significado de uma resposta e o enquadramento de sua entrega respondem a perguntas diferentes. Para um GET comum, 200 OK indica uma recuperação bem-sucedida. 206 Partial Content significa que o servidor está atendendo a uma solicitação de intervalo, transferindo partes selecionadas de uma representação. Dividir a entrega em várias gravações não cria uma solicitação de intervalo. RFC 9110: Semântica HTTP, 206 Partial Content.
Por exemplo, um guia sintético com uma introdução, uma descrição e um parágrafo final pode chegar progressivamente e ainda assim continuar sendo um único documento. Envie os cabeçalhos da resposta uma vez, seguidos dessas seções do corpo em ordem. Não acrescente uma nova linha de status HTTP a cada seção.
A codificação de transferência em partes do HTTP/1.1 envolve os bytes do corpo com comprimentos em hexadecimal e termina com uma parte de tamanho zero e a linha vazia obrigatória de encerramento. Esses bytes de enquadramento delimitam a entrega; não fazem parte do conteúdo do artigo. O remetente não deve combinar Content-Length com Transfer-Encoding. RFC 9112: Codificação de transferência em partes, Content-Length.
A regra prática é deixar a biblioteca HTTP enquadrar a mensagem. Seu aplicativo fornece o conteúdo do documento e sinaliza quando ele terminou.
Qual mecanismo de transmissão em fluxo você deve usar?
O mecanismo compatível depende da versão do HTTP. É possível transmitir um corpo completo em fluxo em todas as três versões abaixo, mas o enquadramento difere entre elas.
| Versão HTTP | Como o conteúdo do corpo é transmitido | Mecanismo de conclusão |
|---|---|---|
| HTTP/1.1 com codificação em partes | Partes com comprimento prefixado | Parte terminal de tamanho zero e seção de trailers concluída |
| HTTP/2 | Quadros DATA |
END_STREAM no quadro final, incluindo a conclusão de qualquer bloco de cabeçalhos |
| HTTP/3 | Quadros DATA |
Conclusão da resposta e fechamento da direção de envio do fluxo |
O HTTP/2 proíbe explicitamente a codificação de transferência em partes do HTTP/1.1. O HTTP/3 não define codificações de transferência e proíbe o cabeçalho Transfer-Encoding. Deixe o servidor implementar o enquadramento do seu protocolo em vez de forçar Transfer-Encoding: chunked em todas as conexões. RFC 9113: Trocas de mensagens HTTP, RFC 9114: Enquadramento de mensagens HTTP.
Para um documento pequeno já montado, enviá-lo normalmente costuma ser a implementação mais simples. Gravações progressivas são úteis quando o conteúdo é produzido ao longo do tempo. O exemplo abaixo espaça deliberadamente três gravações para que você possa observar o comportamento; os atrasos são ilustrativos, não uma recomendação de publicação.
Inicie no seu Mac um documento completo transmitido em fluxo
Abra o Terminal e confira os pré-requisitos:
node --version
curl --version
Se node não estiver disponível, instale uma versão LTS compatível usando a página de download do Node.js e abra uma nova janela do Terminal. O programa usa apenas módulos integrados e não requer pacotes npm.
Cole o bloco completo abaixo no Terminal. Ele inicia um servidor HTTP/1.1 no endereço de demonstração http://127.0.0.1:8080/document. As três strings juntas formam uma única página sintética completa.
node <<'JS'
const http = require('node:http');
const parts = [
'<!doctype html>\n<html lang="en"><head><meta charset="utf-8">' +
'<title>Paper Shapes</title></head><body><main>\n' +
'<h1>Paper Shapes</h1>\n',
'<p>A circle, a square, and a triangle make this sample collection.</p>\n',
'<p>End of the paper shapes guide.</p>\n</main></body></html>\n'
];
const server = http.createServer((req, res) => {
res.on('error', error => console.error(error.message));
if (req.method !== 'GET' || req.url !== '/document') {
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end('No sample document at this path.\n');
return;
}
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
let index = 0;
const timer = setInterval(() => {
if (res.destroyed) {
clearInterval(timer);
return;
}
res.write(parts[index++]);
if (index === parts.length) {
clearInterval(timer);
res.end();
}
}, 300);
res.on('close', () => clearInterval(timer));
});
server.on('error', error => {
console.error(error.message);
process.exitCode = 1;
});
server.listen(8080, '127.0.0.1', () => {
console.log('Sample: http://127.0.0.1:8080/document');
});
JS
O aplicativo chama writeHead() uma vez, write() três vezes e end() uma vez. A documentação do Node descreve gravações sucessivas como partes do mesmo corpo de resposta e exige end() para concluir cada resposta. O Node cuida do enquadramento HTTP; não adicione comprimentos de partes nem um zero terminal às strings. Documentação HTTP do Node.js.
Esta é uma demonstração limitada com três strings pequenas. Para um produtor de grande porte ou contínuo, respeite a contrapressão: quando write() retornar false, pause a produção até drain, tratando também o fechamento e os erros. Documentação do Node.js sobre gravação de respostas.
Deixe esta janela do Terminal aberta. Se ela informar EADDRINUSE, a porta 8080 está ocupada; escolha outra porta disponível no servidor e altere a porta em cada comando do cliente abaixo. Ao terminar, encerre a demonstração com Control-C.
Inspecione o conteúdo decodificado e o enquadramento das partes HTTP
Em uma segunda janela do Terminal, solicite o documento:
curl --http1.1 --include --no-buffer --max-time 5 \
http://127.0.0.1:8080/document
Espere uma resposta 200 OK, um Content-Type de text/html; charset=utf-8 e o conteúdo da página montada. Neste exemplo de HTTP/1.1, a resposta deve usar Transfer-Encoding: chunked. Normalmente, o curl decodifica o enquadramento da transferência, então sua saída comum mostra o documento, e não os tamanhos das partes em hexadecimal.
Para inspecionar o enquadramento, repita a solicitação com --raw:
curl --http1.1 --include --no-buffer --raw --max-time 5 \
http://127.0.0.1:8080/document
A documentação do curl explica que --raw desativa a decodificação interna do conteúdo e das codificações de transferência. --no-buffer desativa o buffer de saída do curl, e --max-time 5 limita a duração da operação. Essas opções fazem deste um comando curto de diagnóstico, em vez de um comando que espera indefinidamente. Manual do curl.
Na saída bruta, linhas de tamanho delimitam o conteúdo, seguidas pela parte terminal de tamanho zero. Sem esse terminador, um corpo HTTP/1.1 em partes está incompleto. Com enquadramento de comprimento fixo, receber menos bytes do que o comprimento declarado também significa que a mensagem está incompleta. RFC 9112: Tratamento de mensagens incompletas.
Use a saída bruta apenas para examinar o transporte. Não copie suas linhas de tamanho para um arquivo de página nem as trate como seções do documento.
Receba o documento inteiro antes de processá-lo
Se a etapa seguinte exigir a página completa, consuma todo o corpo antes de analisá-lo, salvá-lo ou aceitá-lo de outra forma. O WHATWG define o corpo de uma resposta como um fluxo; seu método text() lê o corpo por completo e retorna uma string, rejeitando a operação se o consumo do corpo falhar. Receber apenas os cabeçalhos da resposta não confirma que o corpo terminou. Padrão Fetch do WHATWG: mixin Body, Processamento de respostas.
Com o servidor ainda em execução, cole este cliente completo na segunda janela do Terminal:
node --input-type=module <<'JS'
try {
const response = await fetch('http://127.0.0.1:8080/document', {
signal: AbortSignal.timeout(5000)
});
if (response.status !== 200) {
throw new Error(`Expected 200; received ${response.status}`);
}
const html = await response.text();
const marker = 'End of the paper shapes guide.';
if (!html.includes(marker) || !html.endsWith('</html>\n')) {
throw new Error('Expected sample ending is missing');
}
console.log(html);
console.log('Complete sample document received.');
} catch (error) {
console.error('Document not accepted:', error.message);
process.exitCode = 1;
}
JS
O Node fornece uma implementação de fetch() compatível com navegadores. Seu método AbortSignal.timeout() cria um sinal que aborta após o número especificado de milissegundos; aqui, cinco segundos é um limite ilustrativo para este pequeno exemplo local. Documentação dos objetos globais do Node.js, Documentação sobre o tempo limite de AbortSignal.
O cliente verifica duas coisas diferentes: o consumo bem-sucedido do corpo e o final esperado da amostra. Essa segunda verificação é um diagnóstico específico do aplicativo. O HTTP pode transferir um documento com sucesso mesmo que o aplicativo o tenha encurtado acidentalmente antes de chamar end(). Um marcador de conclusão ajuda a detectar esse erro específico, mas não valida todos os parágrafos nem constitui uma validação geral de HTML.
Este cliente armazena a página inteira na memória. Para documentos muito grandes, escolha um processamento incremental com um formato de documento explícito e regras de conclusão. Não presuma que cada leitura entrega um parágrafo completo ou uma resposta com significado independente.
Diagnostique a conclusão antes de alterar o código de status
Use esta sequência para localizar o problema. Ela separa a conclusão do transporte do conteúdo esperado pelo aplicativo, para que um download aparentemente bem-sucedido não esconda a ausência do trecho final.
| Observação | Próxima ação |
|---|---|
| Não é possível conectar usando o comando local | Confirme que o servidor está em execução e que a porta corresponde. |
| O curl atinge o tempo limite | Verifique se o produtor termina e chama end(); mantenha a saída de erro. |
| A transferência termina, mas a verificação do final falha | Inspecione o conteúdo gerado e o ponto em que o aplicativo encerra a resposta. |
| O documento completo chega de uma só vez | Compare a saída bruta e a decodificada; não deduza que houve várias respostas com base no tempo de exibição. |
Uma solicitação normal da página completa recebe 206 |
Verifique se o tratamento de intervalos foi aplicado sem querer; a entrega progressiva, por si só, não justifica esse código. |
As verificações de conclusão são recomendações derivadas do protocolo e do comportamento do Fetch, e não um recurso HTTP separado. Se a operação de leitura do corpo falhar, o cliente acima informa a falha e termina com erro, em vez de imprimir uma mensagem de sucesso para o conteúdo recebido até aquele momento.
O que isso significa para uma página pública e a Pesquisa Google?
Mantenha o conteúdo útil do documento na própria resposta HTML. O Google explica que o rastreamento e a análise funcionam bem quando o HTML da resposta contém todo o conteúdo da página e recomenda a renderização no servidor ou a pré-renderização, pois nem todo bot executa JavaScript. O exemplo segue essa abordagem: o texto chega diretamente no corpo do documento. Google Search Central: Entenda os conceitos básicos de SEO para JavaScript.
A documentação dos rastreadores do Google informa que uma resposta 200 encaminha o conteúdo recebido para a próxima etapa de processamento; isso não garante a indexação. A documentação citada não especifica um tamanho de parte ou um atraso especial que garanta a indexação de uma página. Trate a transmissão em fluxo como uma implementação de entrega e verifique o conteúdo final separadamente. Google: Como os códigos de status HTTP afetam os rastreadores do Google.
Ao adaptar esta demonstração para hospedagem pública, repita as verificações no endpoint real do documento. Confirme o status de sucesso, consuma todo o corpo e compare o conteúdo final com a página desejada. Mantenha a verificação de aceitação independente do número de gravações, quadros ou atualizações visíveis usados para entregar o documento.
Fontes
- RFC 9110: Semântica HTTP — Editor da RFC / IETF.
- RFC 9112: HTTP/1.1 — Editor da RFC / IETF.
- RFC 9113: HTTP/2 — Editor da RFC / IETF.
- RFC 9114: HTTP/3 — Editor da RFC / IETF.
- Padrão Fetch — WHATWG.
- HTTP — Node.js.
- Objetos globais — Node.js.
- Baixar Node.js — Node.js.
- curl — Como usar — curl.
- Entenda os conceitos básicos de SEO para JavaScript — Google Search Central.
- Como os códigos de status HTTP afetam os rastreadores do Google — Google para Desenvolvedores.