π§ Handling Different Routes
Let's say you want different pages like /, /about, and /contact β each with its own response.
// index.js
import { createServer } from 'node:http';
const server = createServer((req, res) => {
res.setHeader('Content-Type', 'text/plain');
if (req.url === '/') {
res.writeHead(200);
res.end('Welcome to the Home Page!');
} else if (req.url === '/about') {
res.writeHead(200);
res.end('This is the About Page.');
} else if (req.url === '/contact') {
res.writeHead(200);
res.end('Contact us at: example@email.com');
} else {
res.writeHead(404);
res.end('404 Page Not Found');
}
});
server.listen(3000, () => {
console.log('Server running at <http://localhost:3000>');
});req.urlholds the path the browser requested (/,/about,/contact, or anything else) β comparing it in anif/elsechain is how you route different pages.res.setHeader('Content-Type', 'text/plain')tells the browser what kind of content is coming, so it renders the response correctly instead of guessing.res.writeHead(200)explicitly marks the response as successful β technically optional here since200is the default, but writing it makes the intent clear.The fix: the unmatched-route branch now calls
res.writeHead(404)beforeres.end(). Without it, an unknown URL still gets a200 OKstatus even though the page says "Not Found" β which is misleading to browsers, search engines, and any code checking the response status.
βΆοΈ Try It
Run
node index.js
Terminal output:
Server running at <http://localhost:3000>Now visit each route in your browser:
http://localhost:3000/
Status: 200 OK
Body: Welcome to the Home Page!http://localhost:3000/about
Status: 200 OK
Body: This is the About Page.http://localhost:3000/contact
Status: 200 OK
Body: Contact us at: example@email.comhttp://localhost:3000/anything-else
Status: 404 Not Found
Body: 404 Page Not Foundπ‘ With more than a handful of routes, this if/else chain gets unwieldy fast β that's the problem frameworks like Express solve with proper routing.
<div class="infographic-httproutes">
<style>
.infographic-httproutes {
--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;
--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-httproutes[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;
}
.infographic-httproutes * { box-sizing: border-box; }
.infographic-httproutes .r-inner { padding: 0 clamp(1rem, 4vw, 1.5rem); }
.infographic-httproutes .r-eyebrow {
font-size: 0.7rem; font-weight: 600; letter-spacing: 0.09em;
text-transform: uppercase; color: var(--accent); margin: 0 0 0.35rem;
}
.infographic-httproutes 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-httproutes .r-sub { font-size: 0.9rem; color: var(--ink-soft); margin: 0 0 0.7rem; }
.infographic-httproutes .r-boot {
display: inline-block; font-family: 'SFMono-Regular', Consolas, Menlo, monospace; font-size: 0.72rem;
color: var(--ink-soft); background: var(--paper-alt); border: 1px solid var(--line);
border-radius: 999px; padding: 0.28rem 0.75rem; margin-bottom: 1.2rem;
}
.infographic-httproutes .r-boot .r-boot-ok { color: var(--ok); }
/* route picker */
.infographic-httproutes .r-routes { display: flex; gap: 0.45rem; flex-wrap: wrap; margin-bottom: 1rem; }
.infographic-httproutes .r-route-btn {
font-family: 'SFMono-Regular', Consolas, Menlo, monospace; font-size: 0.82rem; font-weight: 600;
color: var(--ink-soft); background: var(--paper); border: 1px solid var(--line);
border-radius: 999px; padding: 0.4rem 0.85rem; cursor: pointer; transition: all 0.15s ease;
}
.infographic-httproutes .r-route-btn:hover { border-color: var(--accent); }
.infographic-httproutes .r-route-btn.is-on { background: var(--accent); border-color: var(--accent); color: #fff; }
.infographic-httproutes .r-custom { display: flex; align-items: center; gap: 0.3rem; }
.infographic-httproutes .r-custom-input {
font-family: 'SFMono-Regular', Consolas, Menlo, monospace; font-size: 0.8rem;
padding: 0.38rem 0.6rem; border: 1px solid var(--line); border-radius: 999px 0 0 999px;
background: var(--paper); color: var(--ink); width: 130px;
}
.infographic-httproutes .r-custom-input:focus { outline: none; border-color: var(--accent); }
.infographic-httproutes .r-custom-go {
font: inherit; font-size: 0.78rem; font-weight: 700; color: #fff; background: var(--ink-soft);
border: none; border-radius: 0 999px 999px 0; padding: 0.4rem 0.75rem; cursor: pointer;
}
.infographic-httproutes .r-custom-go:hover { background: var(--accent); }
/* scene */
.infographic-httproutes .r-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-httproutes .r-scene {
display: grid; grid-template-columns: 1.3fr 84px 0.7fr; align-items: center; gap: 0.4rem;
}
@media (max-width: 560px) { .infographic-httproutes .r-scene { grid-template-columns: 1fr; } }
.infographic-httproutes .r-browser { border: 1px solid var(--line); border-radius: 9px; background: var(--paper); overflow: hidden; }
.infographic-httproutes .r-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-httproutes .r-browser-bar svg { width: 12px; height: 12px; stroke: var(--ink-soft); flex: none; }
.infographic-httproutes .r-browser-url { font-family: 'SFMono-Regular', Consolas, Menlo, monospace; font-size: 0.7rem; color: var(--ink-soft); }
.infographic-httproutes .r-browser-url .r-path { color: var(--accent); font-weight: 700; }
.infographic-httproutes .r-browser-body { min-height: 78px; padding: 0.8rem; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.4rem; }
.infographic-httproutes .r-status-chip {
font-family: 'SFMono-Regular', Consolas, Menlo, monospace; font-size: 0.78rem; font-weight: 700;
border-radius: 999px; padding: 0.22rem 0.65rem; opacity: 0; transform: translateY(4px);
transition: opacity 0.3s ease, transform 0.3s ease;
}
.infographic-httproutes .r-status-chip.is-in { opacity: 1; transform: translateY(0); }
.infographic-httproutes .r-status-chip.is-200 { background: var(--ok-soft); color: var(--ok); border: 1px solid var(--ok); }
.infographic-httproutes .r-status-chip.is-404 { background: var(--charge-soft); color: var(--charge); border: 1px solid var(--charge); }
.infographic-httproutes .r-body-text {
font-size: 0.85rem; text-align: center; color: var(--ink-soft); opacity: 0; transition: opacity 0.3s ease;
}
.infographic-httproutes .r-body-text.is-in { opacity: 1; color: var(--ink); }
.infographic-httproutes .r-actor { display: flex; flex-direction: column; align-items: center; gap: 0.3rem; }
.infographic-httproutes .r-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-httproutes[data-theme="dark"] .r-actor-icon { box-shadow: 0 1px 4px rgba(0,0,0,0.45); }
.infographic-httproutes .r-actor-icon svg { width: 19px; height: 19px; stroke: var(--accent); }
.infographic-httproutes .r-actor-icon.is-busy { transform: scale(1.12); border-color: var(--accent); }
.infographic-httproutes .r-lane { display: flex; flex-direction: column; align-items: center; gap: 0.35rem; }
.infographic-httproutes .r-lane-track { width: 100%; height: 3px; background: var(--line); border-radius: 2px; position: relative; margin: 3px 0; }
.infographic-httproutes .r-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;
}
.infographic-httproutes .r-dot.is-go { opacity: 1; }
.infographic-httproutes .r-dot.at-end { left: 100%; }
.infographic-httproutes .r-dot.is-response { background: var(--ok); }
.infographic-httproutes .r-dot.is-response.is-404 { background: var(--charge); }
.infographic-httproutes .r-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 block */
.infographic-httproutes .r-code {
font-family: 'SFMono-Regular', Consolas, Menlo, monospace; font-size: 0.76rem; line-height: 1.75;
background: var(--paper); border: 1px solid var(--line); border-radius: 9px;
padding: 0.8rem 1rem; color: var(--ink-soft); white-space: pre;
}
.infographic-httproutes .r-code .r-line { display: block; }
.infographic-httproutes .r-code .r-block { display: block; border-radius: 5px; transition: background 0.3s ease, color 0.3s ease; padding: 0 0.3rem; margin: 0 -0.3rem; }
.infographic-httproutes .r-code .r-block.is-hot { background: var(--accent-soft); color: var(--ink); }
.infographic-httproutes .r-code .r-block.is-hot.is-404block { background: var(--charge-soft); }
.infographic-httproutes .r-code .r-kw { color: var(--accent); font-weight: 600; }
.infographic-httproutes .r-code .r-str { color: var(--ok); }
</style>
<div class="r-inner">
<span class="r-boot">$ node index.js β <span class="r-boot-ok">running at localhost:3000</span></span>
<div class="r-routes">
<button class="r-route-btn" data-path="/" type="button">/</button>
<button class="r-route-btn" data-path="/about" type="button">/about</button>
<button class="r-route-btn" data-path="/contact" type="button">/contact</button>
<span class="r-custom">
<input class="r-custom-input" id="rCustomPath" type="text" placeholder="/anything-else" spellcheck="false" />
<button class="r-custom-go" id="rCustomGo" type="button">visit</button>
</span>
</div>
<div class="r-scene-card">
<div class="r-scene">
<div class="r-browser">
<div class="r-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="r-browser-url">localhost:3000<span class="r-path" id="rUrlPath"></span></span>
</div>
<div class="r-browser-body">
<span class="r-status-chip" id="rStatusChip">200</span>
<span class="r-body-text" id="rBodyText">β</span>
</div>
</div>
<div class="r-lane">
<div class="r-actor"><span class="r-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="r-lane-track"><span class="r-dot" id="rDotReq">GET</span></div>
<div class="r-lane-track"><span class="r-dot is-response" id="rDotRes">200</span></div>
<div class="r-actor"><span class="r-actor-icon" id="rServerIcon"><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="r-server-box"><span style="font-size:0.72rem; color:var(--ink-soft);">your server</span></div>
</div>
</div>
<div class="r-code"><span class="r-line"><span class="r-kw">if</span> (req.url === <span class="r-str">'/'</span>) {</span><span class="r-block" id="rBlockHome" style="padding-left:1em;"> res.writeHead(200);
res.end(<span class="r-str">'Welcome to the Home Page!'</span>);</span>
<span class="r-line">} <span class="r-kw">else if</span> (req.url === <span class="r-str">'/about'</span>) {</span><span class="r-block" id="rBlockAbout" style="padding-left:1em;"> res.writeHead(200);
res.end(<span class="r-str">'This is the About Page.'</span>);</span>
<span class="r-line">} <span class="r-kw">else if</span> (req.url === <span class="r-str">'/contact'</span>) {</span><span class="r-block" id="rBlockContact" style="padding-left:1em;"> res.writeHead(200);
res.end(<span class="r-str">'Contact us at: example@email.com'</span>);</span>
<span class="r-line">} <span class="r-kw">else</span> {</span><span class="r-block is-404block" id="rBlockElse" style="padding-left:1em;"> res.writeHead(404);
res.end(<span class="r-str">'404 Page Not Found'</span>);</span>
<span class="r-line">}</span></div>
</div>
<script>
(function () {
var wrapper = document.currentScript.closest('.infographic-httproutes')
|| document.querySelector('.infographic-httproutes');
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 routes = {
'/': { status: 200, body: 'Welcome to the Home Page!', block: 'rBlockHome' },
'/about': { status: 200, body: 'This is the About Page.', block: 'rBlockAbout' },
'/contact': { status: 200, body: 'Contact us at: example@email.com', block: 'rBlockContact' }
};
var routeBtns = Array.prototype.slice.call(wrapper.querySelectorAll('.r-route-btn'));
var customInput = wrapper.querySelector('#rCustomPath');
var customGo = wrapper.querySelector('#rCustomGo');
var urlPath = wrapper.querySelector('#rUrlPath');
var statusChip = wrapper.querySelector('#rStatusChip');
var bodyText = wrapper.querySelector('#rBodyText');
var dotReq = wrapper.querySelector('#rDotReq');
var dotRes = wrapper.querySelector('#rDotRes');
var serverIcon = wrapper.querySelector('#rServerIcon');
var allBlocks = Array.prototype.slice.call(wrapper.querySelectorAll('.r-block'));
var timers = [];
var busy = false;
function clearTimers() { timers.forEach(clearTimeout); timers = []; }
function clearHot() { allBlocks.forEach(function (b) { b.classList.remove('is-hot'); }); }
function visit(path) {
if (busy) return;
busy = true;
var match = routes[path] || { status: 404, body: '404 Page Not Found', block: 'rBlockElse' };
routeBtns.forEach(function (b) { b.classList.toggle('is-on', b.getAttribute('data-path') === path); });
clearTimers();
clearHot();
urlPath.textContent = path;
statusChip.classList.remove('is-in', 'is-200', 'is-404');
bodyText.classList.remove('is-in');
dotReq.classList.remove('is-go', 'at-end');
dotRes.classList.remove('is-go', 'at-end', 'is-404');
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 () {
clearHot();
var el = wrapper.querySelector('#' + match.block);
if (el) el.classList.add('is-hot');
if (match.status === 404) el && el.classList.add('is-404block');
}, t + (reduced ? 0 : 850)));
timers.push(setTimeout(function () {
serverIcon.classList.remove('is-busy');
dotReq.classList.remove('is-go', 'at-end');
dotRes.textContent = String(match.status);
dotRes.classList.toggle('is-404', match.status === 404);
dotRes.classList.add('is-go');
timers.push(setTimeout(function () { dotRes.classList.add('at-end'); }, 20));
}, t + (reduced ? 0 : 1150)));
timers.push(setTimeout(function () {
dotRes.classList.remove('is-go', 'at-end');
statusChip.textContent = match.status === 404 ? '404' : '200';
statusChip.classList.add('is-in', match.status === 404 ? 'is-404' : 'is-200');
bodyText.textContent = match.body;
bodyText.classList.add('is-in');
busy = false;
}, t + (reduced ? 0 : 1750)));
}
routeBtns.forEach(function (btn) {
btn.addEventListener('click', function () { visit(btn.getAttribute('data-path')); });
});
customGo.addEventListener('click', function () {
var p = customInput.value.trim();
if (!p) return;
if (p[0] !== '/') p = '/' + p;
routeBtns.forEach(function (b) { b.classList.remove('is-on'); });
visit(p);
});
customInput.addEventListener('keydown', function (e) { if (e.key === 'Enter') customGo.click(); });
})();
</script>
</div>