Servidores HTTP, Handlers & Padrões ServeMux
net/http roteia requisições através de ServeMux para implementações Handler.
Busque em todas as páginas da documentação
net/http roteia requisições através de ServeMux para implementações Handler.
Go 1.22 modernizou a correspondência de padrões para que rotas REST cientes de método funcionem sem um roteador de terceiros.
Um servidor HTTP escuta em uma porta, analisa requisições e as despacha para handlers.
http.Server envolve o listener com controles de timeout e TLS.
http.ServeMux mapeia padrões de host, método e caminho para handlers.
Handlers implementam ServeHTTP ou usam o adaptador HandlerFunc.
Middleware envolve handlers para adicionar logging, autenticação e métricas antes que sua lógica de negócios seja executada.
Cartão de receita de referência rápida - pronto para copiar e colar.
mux := http.NewServeMux()
mux.HandleFunc("GET /api/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
mux.HandleFunc("GET /api/users/{id}", func(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
fmt.Fprintf(w, `{"id":%q}`, id)
})
srv := &http.Server{Addr: ":8080", Handler: mux, ReadHeaderTimeout: 5 * time.Second}
log.Fatal(srv.ListenAndServe())Quando usar isso:
package main
import (
"encoding/json"
"log"
"net/http"
"strings"
"time"
)
type user struct {
ID string `json:"id"`
Name string `json:"name"`
}
var users = map[string]user{
"1": {ID: "1", Name: "Ada"},
"2": {ID: "2", Name: "Lin"},
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("GET /api/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
})
mux.HandleFunc("GET /api/users/{id}", getUser)
mux.HandleFunc("POST /api/users", createUser)
api := stripPrefix("/api", mux)
srv := &http.Server{
Addr: ":8080",
Handler: logging(api),
ReadHeaderTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 60 * time.Second,
}
log.Fatal(srv.ListenAndServe())
}
func getUser(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
u, ok := users[id]
if !ok {
http.Error(w, "not found", http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(u)
}
func createUser(w http.ResponseWriter, r *http.Request) {
var in user
if err := json.NewDecoder(r.Body).Decode(&in); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
in.ID = "3"
users[in.ID] = in
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
_ = json.NewEncoder(w).Encode(in)
}
func stripPrefix(prefix string, h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
p := strings.TrimPrefix(r.URL.Path, prefix)
if p == "" {
p = "/"
}
r2 := r.Clone(r.Context())
r2.URL.Path = p
h.ServeHTTP(w, r2)
})
}
func logging(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
log.Printf("%s %s %s", r.Method, r.URL.Path, time.Since(start))
})
}O que isso demonstra:
ServeMux dedicado.r.PathValue para segmentos {id}./api.http.Server orientados à produção.ServeMux corresponde ao padrão aplicável mais longo, considerando regras de método e host.ServeHTTP do handler vencedor é executado na goroutine da conexão, a menos que você mesmo crie trabalho.ResponseWriter armazena cabeçalhos em buffer até o primeiro Write ou WriteHeader explícito.| Padrão | Corresponde |
|---|---|
/files/ | Qualquer método, caminhos sob /files/ |
GET /users/{id} | Apenas GET, captura id |
GET /items/{id}/ | GET com segmento de barra final |
{$} | Catch-all para caminhos não correspondentes (use com cuidado) |
// Evite registrar no mux global em bibliotecas:
// http.HandleFunc(...) // ruim em pacotes reutilizáveis
mux := http.NewServeMux() // bom: local, testável
// Rotas com escopo de host:
mux.HandleFunc("GET example.com/admin/", adminHandler)| Tipo | Use quando |
|---|---|
http.HandlerFunc | Handlers de função simples |
Struct com ServeHTTP | Handlers que precisam de dependências (DB, config) |
http.FileServer | Arquivos estáticos |
http.StripPrefix + mux interno | Montar sub-aplicativos |
http.DefaultServeMux em bibliotecas - Importações de terceiros podem registrar rotas conflitantes. Correção: Passe http.NewServeMux() de main.ReadHeaderTimeout - Clientes lentos podem manter conexões sem enviar cabeçalhos. Correção: Defina-o em cada http.Server de produção.Write trava o status em 200. Correção: Chame WriteHeader ou http.Error antes dos bytes do corpo.r.PathValue requer padrões Go 1.22+. Correção: Atualize o Go ou use um roteador como chi./users e /users/ são padrões diferentes. Correção: Registre ambos ou redirecione consistentemente.| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
| chi | Quer grupos de rotas e pilhas de middleware em handlers da biblioteca padrão | Você precisa de zero dependências |
| gorilla/mux | Rotas de regex e restrições de host são centrais | Padrões Go 1.22 já são suficientes |
| gin / echo | Binding, validação e grandes ecossistemas de middleware | Você quer o mínimo de "mágica" e tipos da biblioteca padrão |
Raw ServeMux | API pequena, poucas rotas, apenas biblioteca padrão | Roteamento complexo de regex ou multi-tenant |
Padrões podem incluir métodos HTTP e curingas {name}.
r.PathValue lê segmentos capturados.
A correspondência de prefixo antiga ainda funciona para padrões não qualificados.
Registre padrões separados por método.
Pares de método/caminho não registrados retornam 404; verificações explícitas de método dentro de um handler catch-all podem retornar 405.
Crie múltiplos valores http.Server compartilhando o mesmo handler, cada um com sua própria goroutine ListenAndServe.
Use mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("public")))).
Defina cabeçalhos de cache em middleware de envolvimento, se necessário.
Sim, quando handlers precisam de dependências como *sql.DB.
Armazene as dependências na struct e implemente ServeHTTP uma vez por tipo de rota.
Padrões podem incluir um prefixo de host como api.example.com/.
Útil quando um processo serve múltiplos hosts virtuais.
Ele envolve um handler e limita os bytes do corpo da requisição lidos.
Combine com http.MaxBytesReader para endpoints JSON que aceitam corpos POST.
Use httptest.NewRequest com método e caminho, depois mux.ServeHTTP(rec, req).
Verifique o status e o corpo com httptest.ResponseRecorder.
Sim - cada requisição geralmente é executada em sua própria goroutine.
Proteja o estado compartilhado do handler com mutexes ou confine o estado ao escopo da requisição.
Execute um segundo listener na porta :80 que retorna http.Redirect para URLs TLS, ou termine o TLS no load balancer.
Não com ServeMux puro.
Use portas separadas, cmux, ou um gateway que roteia por protocolo.
Handle registra um http.Handler.
HandleFunc registra uma função através do adaptador HandlerFunc.
Versões do Stack: Esta página foi escrita para Go 1.26.x (GC padrão Green Tea, go fix modernizers - verifique o patch na compilação), chi (latest - verifique na compilação), gin (latest - verifique na compilação), echo (latest - verifique na compilação), google.golang.org/grpc (latest - verifique na compilação), sigs.k8s.io/controller-runtime (latest - verifique na compilação), kubebuilder (latest - verifique na compilação), tinygo (latest - verifique os alvos de placa na compilação), wazero (latest - verifique na compilação), e golangci-lint (latest - verifique o conjunto de linters na compilação).
Revisado por Chris St. John·Última atualização: 16 de jul. de 2026