Ce face net/http.NewServeMux
Un http.ServeMux este un router: primește fiecare cerere, caută modelul care se potrivește cel mai bine cu calea și apelează handler-ul acelui model. http.NewServeMux() creează unul gol, iar mux.HandleFunc și mux.Handle adaugă rute, exact ca funcțiile globale. Routerul este și el un http.Handler, deci îl dai lui ListenAndServe sau lui http.Server.
Din Go 1.22 modelele sunt mai puternice: pot începe cu metoda ("POST /comenzi"), pot avea parametri ("/produse/{id}", citiți cu r.PathValue("id")), un parametru final care prinde restul căii ("/fisiere/{cale...}") și {$} pentru potrivire exactă. Când două modele se potrivesc, câștigă cel mai specific.
Dacă nicio rută nu se potrivește, routerul răspunde 404 Not Found; dacă se potrivește calea, dar nu și metoda, răspunde 405 Method Not Allowed cu antetul Allow.
Ce returnează
NewServeMux: un *http.ServeMux nou, gol.
Exemple
Exemplul 1: Un mic API pentru produse
package main
import (
"fmt"
"io"
"net/http"
"net/http/httptest"
"strings"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("GET /{$}", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Bun venit în magazin")
})
mux.HandleFunc("GET /produse", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Lista produselor: cafea, ceai")
})
mux.HandleFunc("GET /produse/{id}", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Detalii pentru produsul", r.PathValue("id"))
})
mux.HandleFunc("POST /produse", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusCreated)
fmt.Fprintln(w, "Produs adăugat")
})
srv := httptest.NewServer(mux)
defer srv.Close()
cereri := [][2]string{{"GET", "/"}, {"GET", "/produse"}, {"GET", "/produse/17"},
{"POST", "/produse"}, {"DELETE", "/produse"}, {"GET", "/cos"}}
for _, c := range cereri {
req, _ := http.NewRequest(c[0], srv.URL+c[1], nil)
resp, err := http.DefaultClient.Do(req)
if err != nil {
fmt.Println(err)
return
}
corp, _ := io.ReadAll(resp.Body)
resp.Body.Close()
fmt.Printf("%-6s %-11s %d %s\n", c[0], c[1], resp.StatusCode, strings.TrimSpace(string(corp)))
}
}
Rezultat
GET / 200 Bun venit în magazin
GET /produse 200 Lista produselor: cafea, ceai
GET /produse/17 200 Detalii pentru produsul 17
POST /produse 201 Produs adăugat
DELETE /produse 405 Method Not Allowed
GET /cos 404 404 page not found
Exemplul 2: Mux.Handle și testare fără rețea
httptest.NewRecorder ține minte răspunsul, iar mux.ServeHTTP tratează cererea direct, fără server și fără port.
package main
import (
"fmt"
"net/http"
"net/http/httptest"
)
type Stare struct{ Versiune string }
func (s Stare) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "ok, versiunea %s", s.Versiune)
}
func main() {
mux := http.NewServeMux()
mux.Handle("GET /stare", Stare{Versiune: "1.4.2"})
mux.HandleFunc("/fisiere/{cale...}", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "fișierul cerut: %s", r.PathValue("cale"))
})
for _, url := range []string{"/stare", "/fisiere/2026/facturi/f1.pdf"} {
rec := httptest.NewRecorder()
mux.ServeHTTP(rec, httptest.NewRequest("GET", url, nil))
fmt.Println(rec.Code, rec.Body.String())
}
}
Rezultat
200 ok, versiunea 1.4.2
200 fișierul cerut: 2026/facturi/f1.pdf
Greșeli frecvente
- Înregistrezi
"/produse"și te aștepți să prindă și/produse/17. Fără/la final, modelul se potrivește doar cu calea exactă; folosește"/produse/"sau"/produse/{id}". - Scrii două spații sau alt separator între metodă și cale (
"GET /x","GET:/x"). Între metodă și cale trebuie exact un spațiu. - Uiți că un model cu metodă nu există în versiunile Go mai vechi de 1.22 (sau cu
gomai mic îngo.mod):"GET /x"este luat drept cale literală.
Comenzi înrudite
net/http.HandleFunc: Înregistrează o rută în routerul global (DefaultServeMux): HandleFunc primește o funcție, Handle un Handler.net/http.Request.PathValue: Returnează valoarea unui parametru din calea rutei, de exemplu id din modelul „/produse/{id}”.net/http.Handler: Interfața oricărui obiect care răspunde la cereri HTTP (metoda ServeHTTP); HandlerFunc transformă o funcție în Handler.net/http.Server: Serverul HTTP configurabil: adresă, handler, limite de timp; ListenAndServe îl pornește, Shutdown îl oprește curat.