net/http.HandleFunc în Go

Înregistrează o rută în routerul global (DefaultServeMux): HandleFunc primește o funcție, Handle un Handler.

Sintaxă
func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
func Handle(pattern string, handler Handler)

Ce face net/http.HandleFunc

http.HandleFunc("/contact", f) spune: cererile pentru /contact sunt tratate de funcția f. http.Handle face același lucru, dar primește o valoare care implementează interfața http.Handler (are metoda ServeHTTP), de exemplu un http.FileServer.

Rutele ajung în http.DefaultServeMux, routerul global folosit de http.ListenAndServe(addr, nil). Modelele urmează regulile lui ServeMux: "/" prinde tot ce nu se potrivește altundeva, un model terminat în / prinde tot subarborele, iar din Go 1.22 poți scrie metoda și parametri: "GET /produse/{id}".

Routerul global este comod pentru programe mici, dar orice pachet importat îl poate modifica. În aplicații mai mari creează propriul router cu http.NewServeMux(); metodele lui au aceleași nume.

Parametri

Parametru Descriere
pattern Modelul rutei: "/", "/despre", "/static/", "POST /comenzi".
handler Funcția func(w http.ResponseWriter, r *http.Request) (la HandleFunc) sau un http.Handler (la Handle).

Ce returnează

Nimic. Dacă modelul este invalid sau înregistrat de două ori, programul se oprește cu panică.

Exemple

Exemplul 1: Mai multe rute în routerul global

package main

import (
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"
)

type Ora struct{ Oras string }

func (o Ora) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Ora în %s: 14:30\n", o.Oras)
}

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Pagina principală, ai cerut", r.URL.Path)
	})
	http.HandleFunc("/despre", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Magazinul Dexter, Iași")
	})
	http.Handle("/ora", Ora{Oras: "București"})

	srv := httptest.NewServer(http.DefaultServeMux)
	defer srv.Close()
	for _, cale := range []string{"/", "/despre", "/ora", "/altceva"} {
		resp, err := http.Get(srv.URL + cale)
		if err != nil {
			fmt.Println(err)
			return
		}
		corp, _ := io.ReadAll(resp.Body)
		resp.Body.Close()
		fmt.Printf("%-9s -> %s", cale, corp)
	}
}

Rezultat

/         -> Pagina principală, ai cerut /
/despre   -> Magazinul Dexter, Iași
/ora      -> Ora în București: 14:30
/altceva  -> Pagina principală, ai cerut /altceva

Exemplul 2: Metodă și parametru în model (Go 1.22)

GET /salut/{nume} acceptă doar cereri GET; o cerere POST primește 405 Method Not Allowed.

package main

import (
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"
	"strings"
)

func main() {
	http.HandleFunc("GET /salut/{nume}", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Salut, %s!\n", r.PathValue("nume"))
	})
	srv := httptest.NewServer(http.DefaultServeMux)
	defer srv.Close()

	resp, _ := http.Get(srv.URL + "/salut/Maria")
	corp, _ := io.ReadAll(resp.Body)
	resp.Body.Close()
	fmt.Print(resp.StatusCode, " ", string(corp))

	resp, _ = http.Post(srv.URL+"/salut/Maria", "text/plain", strings.NewReader(""))
	resp.Body.Close()
	fmt.Println(resp.Status)
}

Rezultat

200 Salut, Maria!
405 Method Not Allowed

Greșeli frecvente

  • Apelezi funcția în loc să o dai ca valoare: http.HandleFunc("/", acasa()). Scrie http.HandleFunc("/", acasa), fără paranteze.
  • Înregistrezi același model de două ori (de exemplu în teste rulate de mai multe ori): programul se oprește cu panică. Folosește un ServeMux nou pentru fiecare test.
  • Te aștepți ca "/" să prindă doar pagina principală. Prinde orice cale care nu are altă rută; pentru exact „/” folosește modelul "/{$}".

Comenzi înrudite

  • net/http.NewServeMux: Creează un router (ServeMux) propriu care alege handler-ul după metoda și calea cererii; HandleFunc și Handle adaugă rute.
  • 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.ListenAndServe: Pornește un server web pe adresa dată (ex. „:8080”) și răspunde la cereri cu handler-ul dat; rulează până la oprire.
  • net/http.Request.PathValue: Returnează valoarea unui parametru din calea rutei, de exemplu id din modelul „/produse/{id}”.