Verstuur één geslaagde response, schrijf de body stapsgewijs en beëindig het bericht op de gebruikelijke manier. Deze handleiding voor de Mac Terminal laat zien hoe je een volledig synthetisch document verstuurt zonder elke chunk als een aparte response te behandelen of 206 Partial Content te gebruiken.
De taak is om één HTML-pagina te serveren die bedoeld is voor publieke hosting en vervolgens te controleren of een client de volledige inhoud ontvangt. De demonstratie draait lokaal en publiceert niets. Je hebt Terminal, curl en een ondersteunde Node.js LTS-versie nodig van de officiële Node.js-downloadpagina.
Waarom chunks geen gedeeltelijke responses betekenen
De betekenis van een response en de manier waarop die wordt afgebakend, beantwoorden verschillende vragen. Voor een gewone geslaagde GET staat 200 OK voor een geslaagde opvraging. 206 Partial Content betekent dat de server een rangeverzoek uitvoert door geselecteerde delen van een representatie te versturen. De verzending opsplitsen in meerdere schrijfopdrachten maakt er geen rangeverzoek van. RFC 9110: HTTP Semantics, 206 Partial Content.
Een synthetische handleiding met bijvoorbeeld een inleiding, een beschrijving en een afsluitende alinea kan stapsgewijs aankomen en toch één document blijven. Verstuur de responseheaders één keer en daarna de bodysecties in de juiste volgorde. Voeg niet vóór elke sectie een nieuwe HTTP-statusregel toe.
HTTP/1.1-chunked transfercodering omhult bodybytes met lengtes in hexadecimale notatie en eindigt met een chunk van nul bytes en de vereiste afsluitende lege regel. Die framingbytes bakenen de overdracht af; ze zijn geen artikelinhoud. Een afzender mag Content-Length niet combineren met Transfer-Encoding. RFC 9112: Chunked Transfer Coding, Content-Length.
De praktische regel is om de HTTP-bibliotheek het bericht te laten framen. Je applicatie levert documentinhoud aan en geeft aan wanneer die inhoud klaar is.
Welk streamingmechanisme moet je gebruiken?
Het ondersteunde mechanisme hangt af van de HTTP-versie. Een volledige body streamen kan met alle drie de onderstaande versies, maar de framing verschilt.
| HTTP-versie | Hoe de bodyinhoud wordt verzonden | Voltooiingsmechanisme |
|---|---|---|
| HTTP/1.1 met chunked-codering | Chunks voorafgegaan door hun lengte | Afsluitende chunk van nul bytes en voltooide trailersectie |
| HTTP/2 | DATA-frames |
END_STREAM op het afsluitende frame, inclusief voltooiing van elk headerblok |
| HTTP/3 | DATA-frames |
Voltooiing van de response en sluiting van de zendrichting van de stream |
HTTP/2 verbiedt HTTP/1.1-chunked transfercodering expliciet. HTTP/3 definieert geen transfercoderingen en verbiedt de header Transfer-Encoding. Laat de server de framing voor zijn protocol implementeren in plaats van Transfer-Encoding: chunked op elke verbinding af te dwingen. RFC 9113: HTTP Message Exchanges, RFC 9114: HTTP Message Framing.
Voor een klein document dat al is samengesteld, is het meestal het eenvoudigst om het op de gebruikelijke manier te versturen. Stapsgewijs schrijven is handig wanneer inhoud in de loop van de tijd wordt geproduceerd. Het onderstaande voorbeeld spreidt drie schrijfopdrachten bewust uit, zodat je het gedrag kunt bekijken; de vertragingen dienen ter illustratie en zijn geen aanbeveling voor publicatie.
Start een volledig document dat via streaming wordt verstuurd op je Mac
Open Terminal en controleer de vereisten:
node --version
curl --version
Als node niet beschikbaar is, installeer dan een ondersteunde LTS-versie via de Node.js-downloadpagina en open daarna een nieuw Terminal-venster. Het programma gebruikt alleen ingebouwde modules en heeft geen npm-pakketten nodig.
Plak het volledige onderstaande blok in Terminal. Het start een HTTP/1.1-server op het demonstratieadres http://127.0.0.1:8080/document. De drie strings vormen samen één complete synthetische pagina.
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
De applicatie roept writeHead() één keer aan, write() drie keer en end() één keer. Node beschrijft opeenvolgende schrijfopdrachten als delen van dezelfde responsebody en vereist end() om elke response te voltooien. Node verzorgt de HTTP-framing; voeg geen chunklengtes of afsluitende nul toe aan de strings. Node.js HTTP-documentatie.
Dit is een afgebakende demonstratie met drie kleine strings. Houd bij een grote of doorlopende producent rekening met backpressure: wanneer write() false retourneert, pauzeer dan de productie totdat drain, en handel ook sluitingen en fouten af. Node.js-documentatie over response schrijven.
Laat dit Terminal-venster open. Als het EADDRINUSE meldt, is poort 8080 bezet; kies een andere beschikbare poort op de server en wijzig de poort in elk clientcommando hieronder. Stop de demonstratie met Control-C wanneer je klaar bent.
Bekijk zowel de gedecodeerde inhoud als de HTTP-chunkframing
Vraag het document op in een tweede Terminal-venster:
curl --http1.1 --include --no-buffer --max-time 5 \
http://127.0.0.1:8080/document
Je kunt één 200 OK-response verwachten, een Content-Type van text/html; charset=utf-8 en de samengestelde pagina-inhoud. Voor dit HTTP/1.1-voorbeeld gebruikt de response Transfer-Encoding: chunked. Curl decodeert transferframing standaard, dus in de gewone uitvoer zie je het document en niet de hexadecimale chunkgroottes.
Herhaal de aanvraag met --raw om de framing te bekijken:
curl --http1.1 --include --no-buffer --raw --max-time 5 \
http://127.0.0.1:8080/document
Volgens de documentatie van curl schakelt --raw de interne decodering van inhouds- en transfercoderingen uit. --no-buffer schakelt de uitvoerbuffering van curl uit en --max-time 5 begrenst de uitvoeringstijd. Zo wordt dit een korte diagnostische opdracht in plaats van een opdracht die onbeperkt blijft wachten. curl-handleiding.
In de onbewerkte uitvoer staan er regels met groottes rond de inhoud, gevolgd door de afsluitende chunk van nul bytes. Zonder die afsluiter is een HTTP/1.1-body met chunked-codering onvolledig. Bij framing met een vaste lengte is een ontvangst van minder bytes dan de opgegeven lengte onvolledig. RFC 9112: Handling Incomplete Messages.
Gebruik onbewerkte uitvoer alleen om het transport te bekijken. Kopieer de grotteregels niet naar een paginabestand en behandel ze niet als documentsecties.
Ontvang het volledige document voordat je het verwerkt
Als de volgende stap de volledige pagina nodig heeft, lees dan de volledige body uit voordat je die parseert, opslaat of anderszins accepteert. WHATWG definieert een responsebody als een stream; de methode text() leest die body volledig uit en retourneert een string. De methode wijst de bewerking af als het uitlezen van de body mislukt. Alleen responseheaders ontvangen betekent niet dat de body is voltooid. WHATWG Fetch Standard: Body mixin, Processing responses.
Plak deze volledige client in het tweede Terminal-venster terwijl de server nog draait:
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
Node biedt een browsercompatibele implementatie van fetch(). De methode AbortSignal.timeout() maakt een signal dat na het opgegeven aantal milliseconden afbreekt; hier is vijf seconden een illustratieve limiet voor dit kleine lokale voorbeeld. Node.js-documentatie over globale objecten, Documentatie over AbortSignal-time-outs.
De client controleert twee verschillende zaken: het succesvol uitlezen van de body en de verwachte afsluiting van het voorbeeld. Die tweede controle is een applicatiespecifieke diagnose. HTTP kan een document succesvol verzenden dat je applicatie per ongeluk heeft ingekort voordat end() werd aangeroepen. Een afsluitmarkering helpt die specifieke fout op te sporen, maar controleert niet elke alinea en vormt geen algemene HTML-validatie.
Deze client buffert de volledige pagina in het geheugen. Kies voor zeer grote documenten voor incrementele verwerking met een expliciet documentformaat en duidelijke voltooiingsregels. Ga er niet van uit dat elke leesbewerking een volledige alinea of een zelfstandig betekenisvolle response oplevert.
Spoor voltooiing op voordat je de statuscode wijzigt
Gebruik deze volgorde om het probleem te vinden. Hiermee scheid je de voltooiing van het transport van de door de applicatie bedoelde inhoud, zodat een schijnbaar geslaagde download geen ontbrekende afsluiting verbergt.
| Waarneming | Volgende stap |
|---|---|
| Het lokale commando kan geen verbinding maken | Controleer of de server draait en of de poort overeenkomt. |
| Curl loopt vast op de time-out | Controleer of de producent klaar is en end() aanroept; bewaar de foutuitvoer. |
| De overdracht is voltooid, maar de afsluitcontrole mislukt | Controleer de gegenereerde inhoud en waar de applicatie de response beëindigt. |
| Het volledige document komt in één keer aan | Vergelijk de onbewerkte en gedecodeerde uitvoer; leid uit het weergavetijdstip geen meerdere responses af. |
Een gewone aanvraag voor de volledige pagina ontvangt 206 |
Controleer of rangeafhandeling onbedoeld is toegepast; stapsgewijze verzending alleen rechtvaardigt dit niet. |
De voltooiingscontroles zijn aanbevelingen op basis van het protocol en het gedrag van Fetch, geen afzonderlijke HTTP-functie. Als het uitlezen van de body mislukt, meldt de bovenstaande client een fout en eindigt die zonder succes in plaats van een succesmelding te tonen voor de tot dan toe ontvangen inhoud.
Wat betekent dit voor een publieke pagina en Google Search?
Zorg dat de nuttige documentinhoud in de HTML-response zelf staat. Google legt uit dat crawlen en parsen goed werkt voor pagina’s waarvan de response-HTML alle inhoud bevat. Google raadt server-side rendering of prerendering aan, omdat niet elke bot JavaScript uitvoert. Het voorbeeld volgt die aanpak: de tekst komt rechtstreeks in de documentbody aan. Google Search Central: De basisprincipes van JavaScript-SEO begrijpen.
In de documentatie voor crawlers zegt Google dat een 200-response de ontvangen inhoud doorgeeft aan de volgende verwerkingsfase; dat garandeert geen indexering. De aangehaalde documentatie noemt geen speciale chunkgrootte of vertraging die ervoor zorgt dat een pagina wordt geïndexeerd. Behandel streaming als een implementatie voor de overdracht en controleer de voltooide inhoud afzonderlijk. Google: Hoe HTTP-statuscodes de crawlers van Google beïnvloeden.
Herhaal bij het aanpassen van deze demonstratie voor publieke hosting de controles voor het daadwerkelijke documentendpoint. Controleer de geslaagde status, lees de volledige body uit en vergelijk de uiteindelijke inhoud met de bedoelde pagina. Houd de acceptatiecontrole onafhankelijk van het aantal schrijfopdrachten, frames of zichtbare updates waarmee het document is verzonden.
Bronnen
- RFC 9110: HTTP Semantics — RFC Editor / IETF.
- RFC 9112: HTTP/1.1 — RFC Editor / IETF.
- RFC 9113: HTTP/2 — RFC Editor / IETF.
- RFC 9114: HTTP/3 — RFC Editor / IETF.
- Fetch Standard — WHATWG.
- HTTP — Node.js.
- Global objects — Node.js.
- Node.js downloaden — Node.js.
- curl — Gebruik — curl.
- De basisprincipes van JavaScript-SEO begrijpen — Google Search Central.
- Hoe HTTP-statuscodes de crawlers van Google beïnvloeden — Google for Developers.