f in x
HTTP Server in Go — Routing e Middleware con net/http per API Professionali
> cd .. / HUB_EDITORIALE > Visualizza in Inglese
Sviluppo di siti web

HTTP Server in Go — Routing e Middleware con net/http per API Professionali

[2026-06-22] Author: Ing. Calogero Bono

Perché il tuo HTTP server in Go ha bisogno di un sistema di routing e middleware?

Hai iniziato con http.HandleFunc e tutto funzionava. Poi sono arrivati gli endpoint con parametri, l'autenticazione, il logging, la gestione degli errori centralizzata. Il codice si è trasformato in una sequenza di if-else, switch-case e codice duplicato in ogni handler. Il problema non è Go: è che stai usando lo strumento giusto nel modo sbagliato.

Noi di Meteora Web lavoriamo con Go da anni per backend di piattaforme proprietarie. Siamo partiti anche noi dal semplice — poi abbiamo capito che un server HTTP ben strutturato è la differenza tra un progetto che si mantiene e uno che diventa un costo ogni volta che devi aggiungere una rotta.

Questa guida ti mostra come costruire un sistema di routing e middleware che scala, usando esclusivamente la libreria standard di Go (net/http). Niente framework esterni, niente dipendenze inutili. Solo codice che capisci e controlli.

Come funziona il multiplexer net/http in Go?

Il cuore di ogni server HTTP in Go è il http.ServeMux, un multiplexer che associa pattern URL a handler. Fino a Go 1.21, i pattern erano fissi: "/api/users" oppure "/api/" per prefissi. Niente parametri dinamici come :id.

Con Go 1.22 (e versioni successive), il multiplexer supporta pattern con parametri e metodi HTTP. Questo cambia tutto: puoi definire rotte come GET /users/{id} direttamente con la libreria standard, senza pacchetti esterni.

Sponsored Protocol

Esempio base: ServeMux con pattern moderni

package main

import (
	"fmt"
	"log"
	"net/http"
)

func main() {
	mux := http.NewServeMux()

	// Pattern con metodo e parametro dinamico
	mux.HandleFunc("GET /users/{id}", func(w http.ResponseWriter, r *http.Request) {
		id := r.PathValue("id")
		fmt.Fprintf(w, "User ID: %s", id)
	})

	mux.HandleFunc("POST /users", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "User creato")
	})

	log.Fatal(http.ListenAndServe(":8080", mux))
}

Attenzione: r.PathValue() è disponibile da Go 1.22. Se lavori con versioni precedenti, devi usare pacchetti come gorilla/mux o chi — ma il consiglio è aggiornare Go e sfruttare la libreria standard.

Come si implementa il routing avanzato con pattern matching in Go 1.22+?

Il nuovo ServeMux supporta:

  • Metodi HTTP espliciti: GET /risorsa, POST /risorsa, PUT /risorsa/{id}.
  • Parametri dinamici: {id}, {slug}, {path*} per match su più segmenti.
  • Priorità basata su specificità: pattern più specifici vincono su quelli più generici.

Esempio: routing con più metodi e parametri

mux.HandleFunc("GET /posts", listPosts)
mux.HandleFunc("POST /posts", createPost)
mux.HandleFunc("GET /posts/{slug}", getPost)
mux.HandleFunc("PUT /posts/{slug}", updatePost)
mux.HandleFunc("DELETE /posts/{slug}", deletePost)

Nota: non serve più r.Method manuale. Il mux stesso reindirizza gli errori con 405 Method Not Allowed se il metodo non corrisponde.

Sponsored Protocol

Gestione degli asterisco wildcard

Usa {path*} per catturare il resto del percorso:

mux.HandleFunc("GET /files/{path*}", func(w http.ResponseWriter, r *http.Request) {
	path := r.PathValue("path")
	fmt.Fprintf(w, "Path richiesto: %s", path)
})

Come creare middleware componibili per autenticazione, logging e recovery?

Un middleware in Go è una funzione che prende un http.Handler e restituisce un altro http.Handler. La firma standard è:

type Middleware func(http.Handler) http.Handler

Puoi comporre middleware come funzioni annidate. Vediamo i tre più utili per un backend serio.

Middleware di logging

func loggingMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Printf("%s %s %s", r.Method, r.URL.Path, r.RemoteAddr)
		next.ServeHTTP(w, r)
	})
}

Middleware di autenticazione (API Key)

func authMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		key := r.Header.Get("X-API-Key")
		if key != "segreto-super-sicuro" {
			http.Error(w, "Unauthorized", http.StatusUnauthorized)
			return
		}
		next.ServeHTTP(w, r)
	})
}

Middleware di recovery (panic catching)

func recoveryMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if err := recover(); err != nil {
				log.Printf("PANIC: %v", err)
				http.Error(w, "Internal Server Error", http.StatusInternalServerError)
			}
		}()
		next.ServeHTTP(w, r)
	})
}

Comporre i middleware

Usa una funzione helper per applicare più middleware in sequenza:

Sponsored Protocol

func chainMiddleware(handler http.Handler, middlewares ...Middleware) http.Handler {
	for i := len(middlewares) - 1; i >= 0; i-- {
		handler = middlewares[i](handler)
	}
	return handler
}

E poi applichi al mux:

mux := http.NewServeMux()
mux.Handle("GET /protected", chainMiddleware(
	http.HandlerFunc(protectedHandler),
	recoveryMiddleware,
	authMiddleware,
	loggingMiddleware,
))

Oppure, se vuoi applicare middleware globalmente a tutte le rotte, usa un http.Handler wrapper:

Sponsored Protocol

finalHandler := chainMiddleware(mux, recoveryMiddleware, loggingMiddleware)
log.Fatal(http.ListenAndServe(":8080", finalHandler))

Come gestire contesti e pattern decorator per handler complessi?

Spesso hai bisogno di passare dati (utente loggato, connessione DB) da un middleware all'handler. In Go si usa il context.Context tramite r.Context().

Middleware che arricchisce il contesto

func contextMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// esempio: utente estratto dal token
		user := &User{ID: 42, Name: "Mario"}
		ctx := context.WithValue(r.Context(), "user", user)
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}

Nell'handler recuperi il valore:

func protectedHandler(w http.ResponseWriter, r *http.Request) {
	user := r.Context().Value("user").(*User)
	fmt.Fprintf(w, "Benvenuto %s", user.Name)
}

Attenzione: il contesto non va usato come discarica per qualsiasi dato. Usalo solo per valori legati al ciclo di vita della richiesta (autenticazione, trace ID, ecc.).

Quali errori evitare quando si costruisce un HTTP server in Go con net/http?

Ne abbiamo visti parecchi nei progetti che ci arrivano. Ecco i più comuni:

  • Non gestire il body chiuso: usa defer r.Body.Close() in ogni handler che legge il body.
  • Timeout assenti: un server senza timeout muore. Imposta http.Server{ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second}.
  • Middleware globale senza esclusioni: a volte devi bypassare l'autenticazione su rotte di health check. Crea un percorso esplicito o usa pattern di esclusione.
  • Ignorare gli errori di ListenAndServe: http.ListenAndServe torna un errore se il server crasha. Loggalo o lancia panic in fase di sviluppo.

Cosa fare adesso

  1. Aggiorna Go alla versione 1.22+ se non lo hai già fatto. Il nuovo mux è un game changer.
  2. Riscrivi le tue rotte usando pattern con metodo e parametri. Elimina tutto lo switch su r.Method.
  3. Crea un file middleware.go con i middleware di logging, recovery e autenticazione. Sperimenta la composizione.
  4. Testa con httptest — la libreria standard ha httptest.NewServer per testare i tuoi handler senza alzare un server reale.
  5. Se vuoi approfondire l'ecosistema Go per backend, leggi la nostra guida principale su Go per Backend: Concorrenza, API REST e Microservizi.

Un server HTTP ben costruito con net/http ti dà il controllo totale. Nessuna dipendenza, nessuna magia nera. Solo codice che fa esattamente quello che hai scritto. Come piace a noi.

Ing. Calogero Bono

> AUTHOR_EXTRACTED

Ing. Calogero Bono

Ingegnere Informatico, co-fondatore di Meteora Web. Esperto in architetture software, sicurezza informatica e sviluppo sistemi scalabili.
[ Read Full Dossier ]

> METEORA_WEB // WEB AGENCY

Costruiamo la presenza digitale che la tua azienda merita.

Siti web, social, pubblicità online, e-commerce e hosting performante: ingegnerizzati con metodo da ingegneri informatici a Sciacca, per tutta Italia.

> MW_JOURNAL

> READ_ALL()