Created
February 20, 2025 20:55
-
-
Save wesbos/1d8c27777c131cf408915872bc68f47d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const http = require('http'); | |
const MAX_AGE = 5; // seconds | |
const STALE_WHILE_REVALIDATE = 200; // seconds | |
const server = http.createServer((req, res) => { | |
// Set cache control headers | |
res.setHeader('Cache-Control', `max-age=${MAX_AGE}, stale-while-revalidate=${STALE_WHILE_REVALIDATE}`); | |
// Get current time | |
const now = new Date(); | |
const currentTime = now.toLocaleTimeString(); | |
const currentTimestamp = Date.now(); | |
console.log(`Generating a new Response!`, currentTime); | |
// Send HTML response | |
res.writeHead(200, { 'Content-Type': 'text/html' }); | |
res.end(` | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<link rel="icon" href="https://fav.farm/🔥" /> | |
<meta charset="UTF-8"> | |
<title>Time Server</title> | |
<style> | |
body { | |
font-family: system-ui, sans-serif; | |
max-width: 800px; | |
margin: 0 auto; | |
padding: 2rem; | |
line-height: 1.5; | |
} | |
.time { | |
font-size: 2rem; | |
font-weight: bold; | |
margin: 1rem 0; | |
} | |
.elapsed { | |
color: #666; | |
} | |
.cached { | |
background: #ffd70033; | |
padding: 1rem; | |
border-radius: 4px; | |
margin: 1rem 0; | |
} | |
.status { | |
padding: 0.5rem 1rem; | |
border-radius: 4px; | |
display: inline-block; | |
margin: 1rem 0; | |
} | |
.status.fresh { | |
background: #d4edda; | |
color: #155724; | |
} | |
.status.stale { | |
background: #fff3cd; | |
color: #856404; | |
} | |
.refresh-link { | |
display: inline-block; | |
padding: 0.5rem 1rem; | |
background: #007bff; | |
color: white; | |
text-decoration: none; | |
border-radius: 4px; | |
margin: 1rem 0; | |
} | |
.refresh-link:hover { | |
background: #0056b3; | |
} | |
.refresh-status { | |
margin: 1rem 0; | |
font-style: italic; | |
} | |
</style> | |
</head> | |
<body> | |
<h1>Time Server</h1> | |
<div id="status"></div> | |
<div class="time">Server time: <span id="serverTime">${currentTime}</span></div> | |
<div class="elapsed">Time elapsed since server generated this response: <span id="elapsedTime">0</span> seconds</div> | |
<div id="refreshStatus" class="refresh-status"></div> | |
<a href="/" class="refresh-link">↻ Refresh Page</a> | |
<div class="cached"> | |
<strong>How this works:</strong> | |
<ul> | |
<li>This response can be cached for ${MAX_AGE} seconds (max-age=${MAX_AGE})</li> | |
<li>After ${MAX_AGE} seconds, it can serve stale content for up to ${STALE_WHILE_REVALIDATE} seconds while revalidating</li> | |
<li>The elapsed time shows how old this response is - if it's more than ${MAX_AGE} seconds, you're seeing a stale response!</li> | |
</ul> | |
</div> | |
<script> | |
const serverTimestamp = ${currentTimestamp}; | |
const maxAge = ${MAX_AGE}; | |
const elapsedTime = document.getElementById('elapsedTime'); | |
const status = document.getElementById('status'); | |
const refreshStatus = document.getElementById('refreshStatus'); | |
// Calculate initial elapsed time and set status once | |
const initialElapsed = Math.floor((Date.now() - serverTimestamp) / 1000); | |
const isStale = initialElapsed > maxAge; | |
// Set the status once on page load | |
status.className = isStale ? 'status stale' : 'status fresh'; | |
status.textContent = isStale | |
? '🔄 This response was served from a stale cache' | |
: '✨ This response was fresh'; | |
// Set initial elapsed time | |
elapsedTime.textContent = initialElapsed; | |
// Update elapsed time counter and refresh message | |
setInterval(() => { | |
const elapsed = Math.floor((Date.now() - serverTimestamp) / 1000); | |
elapsedTime.textContent = elapsed; | |
// Update the refresh status message | |
if (elapsed <= maxAge) { | |
refreshStatus.textContent = \`If you refresh now, you'll get a fresh response from cache (still within max-age of \${maxAge} seconds)\`; | |
} else if (elapsed <= maxAge + ${STALE_WHILE_REVALIDATE}) { | |
refreshStatus.textContent = \`If you refresh now, you'll get a stale response while the server revalidates (stale for \${elapsed - maxAge} seconds)\`; | |
} else { | |
refreshStatus.textContent = \`If you refresh now, you'll get a fresh response (cache expired)\`; | |
} | |
}, 1000); | |
</script> | |
</body> | |
</html> | |
`); | |
}); | |
const PORT = 6969; | |
server.listen(PORT, () => { | |
console.log(`Server running on port http://localhost:${PORT}`); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment