Reading — step 1 of 5
Read
~1 min readProduction Features
Putting It All Together
You now have every piece. The full server is a state machine on top of TCP:
listen(port)
loop:
conn = accept()
spawn handle_connection(conn):
while True:
request = parse_request(conn) # request line + headers + body
if not request: break # malformed or EOF
handler = router.match(request)
response = handler(request)
response.headers["Date"] = now_rfc1123()
response.headers["Server"] = "MyServer/1.0"
send_response(conn, response)
access_log(request, response)
metrics.record(request, response)
if should_close(request, response): break
close(conn)
What separates a hobby implementation from production:
- Timeouts everywhere: idle, read, write, total request. Without these, one slow client can hold a worker forever.
- Graceful shutdown: SIGTERM -> stop accepting -> drain in-flight requests -> exit. Lets a load balancer remove you cleanly.
- Limits: max header size (8 KB), max body size (configurable), max request line length (8 KB), max headers per request (~100).
- TLS: in production you serve HTTPS, not HTTP. Termination usually happens at a load balancer (nginx, envoy, AWS ALB).
- HTTP/2: completely different framing — binary, multiplexed, server-push. HTTP/3 runs over QUIC. The above design is HTTP/1.1 only.
You now know how nginx, Apache, Caddy, and Go's net/http actually work.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…