π¦ Headers & Status Codes
Headers tell the browser how to interpret the response β is it HTML, JSON, plain text? Status codes tell it whether the request actually succeeded, failed, or something else happened.
// index.js
import { createServer } from 'node:http';
const server = createServer((req, res) => {
res.statusCode = 200; // OK
res.setHeader('Content-Type', 'text/plain');
res.end('Everything is working fine!');
});
server.listen(3000, () => {
console.log('Header + Status Code example: <http://localhost:3000>');
});res.statusCode = 200sets the response status β200means "OK, the request succeeded." It's set separately from the body content.res.setHeader(name, value)attaches metadata to the response β here, telling the browser to expect plain text.Both of these need to be set before
res.end()is called β once the response starts sending, headers and status code can no longer change.
π» Terminal output:
Header + Status Code example: <http://localhost:3000>π Browser output β visiting http://localhost:3000 shows:
Everything is working fine!(Status: 200 OK, visible in your browser's dev tools under the Network tab.)
β¨ Shorthand: res.writeHead()
Setting the status code and headers separately works, but res.writeHead() combines both into a single call.
res.writeHead(200, { 'Content-Type': 'text/plain' });This one line does what res.statusCode = 200 + res.setHeader(...) did together:
π’ Sets the status code (
200)π Sends the headers, as an object of key-value pairs
// index.js
import { createServer } from 'node:http';
const server = createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Everything is working fine!');
});
server.listen(3000, () => {
console.log('Shorthand example: <http://localhost:3000>');
});Same terminal and browser output as above β writeHead() is just a more compact way to write the exact same response.
π’ Common Status Codes to Know
β
200 OKβ request succeededβ
201 Createdβ a new resource was created (common after a POST)βͺοΈ
301 / 302β the resource has moved, redirect to a new URLβ
404 Not Foundβ no resource exists at that URLπ«
403 Forbiddenβ the client isn't allowed to access thisπ₯
500 Internal Server Errorβ something broke on the server's side
<div class="infographic-httpstatus">
<style>
.infographic-httpstatus {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--ok: #1f9d55;
--ok-soft: #e5f6ec;
--charge: #c23b3b;
--charge-soft:#fbe6e6;
--warn: #b8792c;
--warn-soft: #fbeee0;
--radius: 10px;
box-sizing: border-box;
max-width: 880px;
margin: 0 auto;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
color: var(--ink);
background: transparent;
}
.infographic-httpstatus[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #13171F;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
--ok: #34d399;
--ok-soft: #163227;
--charge: #e2685f;
--charge-soft:#3a2020;
--warn: #d9a15c;
--warn-soft: #3a2d18;
}
.infographic-httpstatus * { box-sizing: border-box; }
.infographic-httpstatus .s-inner { padding: 0 clamp(1rem, 4vw, 1.5rem); }
.infographic-httpstatus .s-eyebrow {
font-size: 0.7rem; font-weight: 600; letter-spacing: 0.09em;
text-transform: uppercase; color: var(--accent); margin: 0 0 0.35rem;
}
.infographic-httpstatus h2 {
font-family: 'Newsreader', Georgia, serif; font-weight: 600;
font-size: clamp(1.5rem, 4vw, 2rem); line-height: 1.15;
margin: 0 0 0.3rem; letter-spacing: -0.01em;
}
.infographic-httpstatus .s-sub { font-size: 0.9rem; color: var(--ink-soft); margin: 0 0 1.1rem; }
/* style toggle */
.infographic-httpstatus .s-style-row { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 1rem; flex-wrap: wrap; }
.infographic-httpstatus .s-style-btn {
font-family: 'SFMono-Regular', Consolas, Menlo, monospace; font-size: 0.76rem; font-weight: 600;
color: var(--ink-soft); background: var(--paper); border: 1px solid var(--line);
border-radius: 999px; padding: 0.35rem 0.75rem; cursor: pointer; transition: all 0.15s ease;
}
.infographic-httpstatus .s-style-btn:hover { border-color: var(--accent); }
.infographic-httpstatus .s-style-btn.is-on { background: var(--accent); border-color: var(--accent); color: #fff; }
.infographic-httpstatus .s-style-eq { font-size: 0.72rem; color: var(--ink-soft); }
/* status chips */
.infographic-httpstatus .s-chips { display: flex; gap: 0.4rem; flex-wrap: wrap; margin-bottom: 1rem; }
.infographic-httpstatus .s-chip {
font-family: 'SFMono-Regular', Consolas, Menlo, monospace; font-size: 0.78rem; font-weight: 700;
border: 1px solid var(--line); background: var(--paper); color: var(--ink-soft);
border-radius: 999px; padding: 0.38rem 0.8rem; cursor: pointer; transition: all 0.15s ease;
}
.infographic-httpstatus .s-chip:hover { border-color: var(--accent); }
.infographic-httpstatus .s-chip.is-on.cat-2xx { background: var(--ok); border-color: var(--ok); color: #fff; }
.infographic-httpstatus .s-chip.is-on.cat-3xx { background: var(--accent); border-color: var(--accent); color: #fff; }
.infographic-httpstatus .s-chip.is-on.cat-4xx { background: var(--warn); border-color: var(--warn); color: #fff; }
.infographic-httpstatus .s-chip.is-on.cat-5xx { background: var(--charge); border-color: var(--charge); color: #fff; }
/* scene */
.infographic-httpstatus .s-scene-card {
border: 1px solid var(--line); border-radius: var(--radius); background: var(--paper-alt);
padding: 1.1rem 1.1rem 1.2rem; margin-bottom: 1rem;
}
.infographic-httpstatus .s-scene { display: grid; grid-template-columns: 1.3fr 84px 0.7fr; align-items: center; gap: 0.4rem; }
@media (max-width: 560px) { .infographic-httpstatus .s-scene { grid-template-columns: 1fr; } }
.infographic-httpstatus .s-browser { border: 1px solid var(--line); border-radius: 9px; background: var(--paper); overflow: hidden; }
.infographic-httpstatus .s-browser-bar { display: flex; align-items: center; gap: 0.4rem; padding: 0.4rem 0.55rem; background: var(--paper-alt); border-bottom: 1px solid var(--line); }
.infographic-httpstatus .s-browser-bar svg { width: 12px; height: 12px; stroke: var(--ink-soft); flex: none; }
.infographic-httpstatus .s-browser-url { font-family: 'SFMono-Regular', Consolas, Menlo, monospace; font-size: 0.7rem; color: var(--ink-soft); }
.infographic-httpstatus .s-browser-body { min-height: 90px; padding: 0.8rem; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.5rem; }
.infographic-httpstatus .s-status-icon {
width: 34px; height: 34px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
opacity: 0; transform: scale(0.7); transition: opacity 0.3s ease, transform 0.3s ease;
}
.infographic-httpstatus .s-status-icon.is-in { opacity: 1; transform: scale(1); }
.infographic-httpstatus .s-status-icon svg { width: 18px; height: 18px; stroke: #fff; }
.infographic-httpstatus .s-status-icon.cat-2xx { background: var(--ok); }
.infographic-httpstatus .s-status-icon.cat-3xx { background: var(--accent); }
.infographic-httpstatus .s-status-icon.cat-4xx { background: var(--warn); }
.infographic-httpstatus .s-status-icon.cat-5xx { background: var(--charge); }
.infographic-httpstatus .s-status-chip {
font-family: 'SFMono-Regular', Consolas, Menlo, monospace; font-size: 0.85rem; font-weight: 700;
opacity: 0; transition: opacity 0.3s ease;
}
.infographic-httpstatus .s-status-chip.is-in { opacity: 1; }
.infographic-httpstatus .s-status-chip.cat-2xx { color: var(--ok); }
.infographic-httpstatus .s-status-chip.cat-3xx { color: var(--accent); }
.infographic-httpstatus .s-status-chip.cat-4xx { color: var(--warn); }
.infographic-httpstatus .s-status-chip.cat-5xx { color: var(--charge); }
.infographic-httpstatus .s-placeholder { color: var(--ink-soft); font-family: 'SFMono-Regular', Consolas, Menlo, monospace; font-size: 0.85rem; }
.infographic-httpstatus .s-actor { display: flex; flex-direction: column; align-items: center; gap: 0.3rem; }
.infographic-httpstatus .s-actor-icon {
width: 38px; height: 38px; border-radius: 10px; background: var(--paper); border: 1px solid var(--line);
display: flex; align-items: center; justify-content: center;
box-shadow: 0 1px 3px rgba(0,0,0,0.10), 0 1px 1px rgba(0,0,0,0.06);
transition: transform 0.2s ease, border-color 0.2s ease;
}
.infographic-httpstatus[data-theme="dark"] .s-actor-icon { box-shadow: 0 1px 4px rgba(0,0,0,0.45); }
.infographic-httpstatus .s-actor-icon svg { width: 19px; height: 19px; stroke: var(--accent); }
.infographic-httpstatus .s-actor-icon.is-busy { transform: scale(1.12); border-color: var(--accent); }
.infographic-httpstatus .s-lane { display: flex; flex-direction: column; align-items: center; gap: 0.35rem; }
.infographic-httpstatus .s-lane-track { width: 100%; height: 3px; background: var(--line); border-radius: 2px; position: relative; margin: 3px 0; }
.infographic-httpstatus .s-dot {
position: absolute; top: 50%; transform: translate(-50%, -50%); left: 0;
padding: 0.13rem 0.4rem; border-radius: 999px; font-size: 0.58rem; font-weight: 700;
font-family: 'SFMono-Regular', Consolas, Menlo, monospace; white-space: nowrap;
opacity: 0; background: var(--accent); color: #fff; transition: left 0.55s ease, opacity 0.2s ease, background 0.2s ease;
}
.infographic-httpstatus .s-dot.is-go { opacity: 1; }
.infographic-httpstatus .s-dot.at-end { left: 100%; }
.infographic-httpstatus .s-server-box { display: flex; align-items: center; justify-content: center; padding: 0.8rem; border: 1px solid var(--line); border-radius: 9px; background: var(--paper); }
/* code box */
.infographic-httpstatus .s-code {
font-family: 'SFMono-Regular', Consolas, Menlo, monospace; font-size: 0.79rem; line-height: 1.85;
background: var(--paper); border: 1px solid var(--line); border-radius: 9px;
padding: 0.75rem 1rem; color: var(--ink-soft); white-space: pre;
}
.infographic-httpstatus .s-code .s-kw { color: var(--accent); font-weight: 600; }
.infographic-httpstatus .s-code .s-str { color: var(--ok); }
.infographic-httpstatus .s-code .s-num { color: var(--warn); font-weight: 700; }
</style>
<div class="s-inner">
<div class="s-style-row">
<button class="s-style-btn is-on" data-style="separate" type="button">statusCode + setHeader</button>
<span class="s-style-eq">β‘</span>
<button class="s-style-btn" data-style="shorthand" type="button">writeHead()</button>
</div>
<div class="s-chips" id="sChips">
<button class="s-chip" data-code="200" data-cat="2xx" data-label="OK" type="button">200 OK</button>
<button class="s-chip" data-code="201" data-cat="2xx" data-label="Created" type="button">201 Created</button>
<button class="s-chip" data-code="301" data-cat="3xx" data-label="Moved" type="button">301 Redirect</button>
<button class="s-chip" data-code="404" data-cat="4xx" data-label="Not Found" type="button">404 Not Found</button>
<button class="s-chip" data-code="403" data-cat="4xx" data-label="Forbidden" type="button">403 Forbidden</button>
<button class="s-chip" data-code="500" data-cat="5xx" data-label="Server Error" type="button">500 Error</button>
</div>
<div class="s-scene-card">
<div class="s-scene">
<div class="s-browser">
<div class="s-browser-bar">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
<span class="s-browser-url">localhost:3000</span>
</div>
<div class="s-browser-body" id="sBrowserBody"><span class="s-placeholder">pick a status & watch</span></div>
</div>
<div class="s-lane">
<div class="s-actor"><span class="s-actor-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg></span></div>
<div class="s-lane-track"><span class="s-dot" id="sDotReq">GET</span></div>
<div class="s-lane-track"><span class="s-dot" id="sDotRes"></span></div>
<div class="s-actor"><span class="s-actor-icon" id="sServerIcon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="8" x="2" y="2" rx="2" ry="2"/><rect width="20" height="8" x="2" y="14" rx="2" ry="2"/><line x1="6" x2="6.01" y1="6" y2="6"/><line x1="6" x2="6.01" y1="18" y2="18"/></svg></span></div>
</div>
<div class="s-server-box"><span style="font-size:0.72rem; color:var(--ink-soft);">your server</span></div>
</div>
<div class="s-code" id="sCode"></div>
</div>
</div>
<script>
(function () {
var wrapper = document.currentScript.closest('.infographic-httpstatus')
|| document.querySelector('.infographic-httpstatus');
var bodyAttr = document.body.getAttribute('data-darkmode');
var dark;
if (bodyAttr === 'true') { dark = true; }
else if (bodyAttr === 'false') { dark = false; }
else {
var m = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = m ? m[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
var reduced = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
var icons = {
'2xx': '<path d="M21.801 10A10 10 0 1 1 17 3.335"/><path d="m9 11 3 3L22 4"/>',
'2xx-201': '<circle cx="12" cy="12" r="10"/><path d="M8 12h8"/><path d="M12 8v8"/>',
'3xx': '<path d="m15 14 5-5-5-5"/><path d="M4 20v-7a4 4 0 0 1 4-4h12"/>',
'4xx': '<circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/>',
'4xx-403': '<path d="M19 16v-2a2 2 0 0 0-4 0v2"/><path d="M9.5 15H7a4 4 0 0 0-4 4v2"/><circle cx="10" cy="7" r="4"/><rect x="13" y="16" width="8" height="5" rx=".899"/>',
'5xx': '<path d="m10.852 14.772-.383.923"/><path d="M13.148 14.772a3 3 0 1 0-2.296-5.544l-.383-.923"/><path d="m13.148 9.228.383-.923"/><path d="m13.53 15.696-.382-.924a3 3 0 1 1-2.296-5.544"/><path d="m14.772 10.852.923-.383"/><path d="m14.772 13.148.923.383"/><path d="M4.5 10H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-.5"/><path d="M4.5 14H4a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-4a2 2 0 0 0-2-2h-.5"/><path d="M6 18h.01"/><path d="M6 6h.01"/><path d="m9.228 10.852-.923-.383"/><path d="m9.228 13.148-.923.383"/>'
};
function iconFor(code, cat) {
if (code === '201') return icons['2xx-201'];
if (code === '403') return icons['4xx-403'];
return icons[cat];
}
var styleBtns = Array.prototype.slice.call(wrapper.querySelectorAll('.s-style-btn'));
var chips = Array.prototype.slice.call(wrapper.querySelectorAll('#sChips .s-chip'));
var codeBox = wrapper.querySelector('#sCode');
var browserBody = wrapper.querySelector('#sBrowserBody');
var dotReq = wrapper.querySelector('#sDotReq');
var dotRes = wrapper.querySelector('#sDotRes');
var serverIcon = wrapper.querySelector('#sServerIcon');
var currentStyle = 'separate';
var currentChip = null;
var timers = [];
var busy = false;
function clearTimers() { timers.forEach(clearTimeout); timers = []; }
var catColor = { '2xx': '#1f9d55', '3xx': 'var(--accent)', '4xx': 'var(--warn)', '5xx': 'var(--charge)' };
function renderCode(code, cat, label) {
var num = code ? '<span class="s-num">' + code + '</span>' : '<span class="s-num">200</span>';
if (currentStyle === 'separate') {
codeBox.innerHTML =
'res.statusCode = ' + num + '; <span style="opacity:.6">// ' + (label || 'OK') + '</span>\n' +
"res.<span class=\"s-kw\">setHeader</span>('Content-Type', <span class=\"s-str\">'text/plain'</span>);\n" +
'res.<span class="s-kw">end</span>();';
} else {
codeBox.innerHTML =
'res.<span class="s-kw">writeHead</span>(' + num + ', { <span class="s-str">\'Content-Type\'</span>: <span class="s-str">\'text/plain\'</span> });\n' +
'res.<span class="s-kw">end</span>();';
}
}
renderCode(null, null, null);
styleBtns.forEach(function (btn) {
btn.addEventListener('click', function () {
styleBtns.forEach(function (b) { b.classList.remove('is-on'); });
btn.classList.add('is-on');
currentStyle = btn.getAttribute('data-style');
renderCode(currentChip ? currentChip.code : null, currentChip ? currentChip.cat : null, currentChip ? currentChip.label : null);
});
});
function visit(code, cat, label) {
if (busy) return;
busy = true;
clearTimers();
currentChip = { code: code, cat: cat, label: label };
chips.forEach(function (c) { c.classList.remove('is-on', 'cat-2xx', 'cat-3xx', 'cat-4xx', 'cat-5xx'); });
var activeChip = wrapper.querySelector('.s-chip[data-code="' + code + '"]');
if (activeChip) activeChip.classList.add('is-on', 'cat-' + cat);
renderCode(code, cat, label);
browserBody.innerHTML = '<span class="s-placeholder">loading\u2026</span>';
dotReq.classList.remove('is-go', 'at-end');
dotRes.classList.remove('is-go', 'at-end', 'cat-2xx', 'cat-3xx', 'cat-4xx', 'cat-5xx');
dotRes.style.background = '';
var t = reduced ? 0 : 40;
timers.push(setTimeout(function () {
dotReq.classList.add('is-go');
timers.push(setTimeout(function () { dotReq.classList.add('at-end'); }, 20));
}, t));
timers.push(setTimeout(function () { serverIcon.classList.add('is-busy'); }, t + (reduced ? 0 : 550)));
timers.push(setTimeout(function () {
serverIcon.classList.remove('is-busy');
dotReq.classList.remove('is-go', 'at-end');
dotRes.textContent = code;
dotRes.classList.add('cat-' + cat, 'is-go');
dotRes.style.background = cat === '2xx' ? '#1f9d55' : cat === '3xx' ? '' : cat === '4xx' ? 'var(--warn)' : 'var(--charge)';
timers.push(setTimeout(function () { dotRes.classList.add('at-end'); }, 20));
}, t + (reduced ? 0 : 1000)));
timers.push(setTimeout(function () {
dotRes.classList.remove('is-go', 'at-end');
browserBody.innerHTML =
'<span class="s-status-icon cat-' + cat + '"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' + iconFor(code, cat) + '</svg></span>' +
'<span class="s-status-chip cat-' + cat + '">' + code + ' ' + label + '</span>';
requestAnimationFrame(function () {
wrapper.querySelector('.s-status-icon').classList.add('is-in');
wrapper.querySelector('.s-status-chip').classList.add('is-in');
});
busy = false;
}, t + (reduced ? 0 : 1650)));
}
chips.forEach(function (chip) {
chip.addEventListener('click', function () {
visit(chip.getAttribute('data-code'), chip.getAttribute('data-cat'), chip.getAttribute('data-label'));
});
});
})();
</script>
</div>