How Go’s Built‑in HTTP Server Handles Connections and Requests

This article walks through building a minimal Go HTTP server, explains how ListenAndServe internally binds, listens, and accepts connections, details the server’s main loop, request handling, routing logic, and shows how to customize connection and state hooks with concrete code examples.

Liangxu Linux
Liangxu Linux
Liangxu Linux
How Go’s Built‑in HTTP Server Handles Connections and Requests

Creating a Minimal Go HTTP Server

Using only 15 lines of Go code you can start an HTTP server that listens on port 81 and responds with "hello world". The essential code is:

package main

import (
    "io"
    "net/http"
)

func main() {
    http.HandleFunc("/hello", hello)
    http.ListenAndServe(":81", nil)
}

func hello(response http.ResponseWriter, request *http.Request) {
    io.WriteString(response, "hello world")
}

The server can be compiled into a single binary, making deployment straightforward.

How ListenAndServe Works

The call http.ListenAndServe(":81", nil) performs two tasks: it binds to the address and port, and it starts serving incoming connections. Internally it wraps the OS system calls bind, listen and accept, then enters a loop that accepts connections and launches a new goroutine for each.

The first argument, Addr, specifies the listening address; the second, Handler, is usually nil, which means the default http.DefaultServeMux will be used.

Connection‑level Hooks: ConnContext

Each new connection receives a context derived from a base context. The ConnContext field of http.Server allows you to modify this context before the request is processed. A custom server can be created as follows:

func main() {
    http.HandleFunc("/hello", hello)
    server := http.Server{
        Addr: ":81",
        ConnContext: func(ctx context.Context, c net.Conn) context.Context {
            return context.WithValue(ctx, "hello", "roshi")
        },
    }
    server.ListenAndServe()
}

Similarly, the ConnState hook lets you run a callback whenever a connection changes state.

Request Processing Loop

After a connection is accepted, the server runs a serve loop that repeatedly reads requests from the same connection:

func (c *conn) serve(ctx context.Context) {
    for {
        w, err := c.readRequest(ctx)
        // error handling omitted
        serverHandler{c.server}.ServeHTTP(w, w.req)
    }
}

This design allows a single TCP connection to handle multiple HTTP requests (HTTP keep‑alive). After reading a request, the server may start a background read to pre‑fetch the next request, improving throughput.

Routing Mechanics

The ServeHTTP method looks up the registered handler based on the request URI and method. Special cases such as the * pattern or the OPTIONS method are handled by a global options handler.

Routing follows three simple rules:

If a route was registered with a host, the lookup uses host+path; otherwise it matches by path only.

Exact matches take precedence. If a pattern ends with /, prefix matching is also applied.

Examples:

http.HandleFunc("/hello", hello)
http.HandleFunc("127.0.0.1/hello", hello2)

// curl 'http://127.0.0.1:81/hello' → hello2
// curl 'http://localhost:81/hello' → hello

With a trailing slash:

http.HandleFunc("/hello", hello)
http.HandleFunc("127.0.0.1/hello/", hello2)

// curl 'http://127.0.0.1:81/hello/roshi' → hello2

Key Takeaways

Starting a Go HTTP server is extremely simple.

The server runs a main accept loop that spawns a goroutine for each new connection.

Each connection runs its own request‑handling loop, performing request parsing, routing, and handler execution.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendconcurrencyGoNetworking
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.