Fundamentos de net/http
9 ejemplos para empezar con net/http: 7 básicos y 2 intermedios.
Busca en todas las páginas de la documentación
9 ejemplos para empezar con net/http: 7 básicos y 2 intermedios.
mkdir httplab && cd httplab && go mod init example.com/httplab.main.go (o archivos separados en un mismo paquete) y ejecuta con go run ..Una función con la firma func(http.ResponseWriter, *http.Request) puede servir HTTP directamente.
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "hello")
})
http.ListenAndServe(":8080", nil)
}http.HandleFunc se registra en http.DefaultServeMux.nil a ListenAndServe usa ese mux por defecto.ServeMux dedicado en servicios reales para evitar colisiones de rutas globales.Relacionado: net/http: La Pila HTTP Incluida de Go - descripción conceptual
Aísla las rutas en un mux que poseas en lugar del predeterminado global.
package main
import (
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
})
http.ListenAndServe(":8080", mux)
}http.NewServeMux() devuelve un enrutador vacío.ListenAndServe.Relacionado: Patrones de Servidores, Handlers y ServeMux HTTP - patrones de Go 1.22+
Registra rutas con el método HTTP y segmentos {param} en una sola llamada.
package main
import (
"fmt"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("GET /users/{id}", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "user=%s", r.PathValue("id"))
})
http.ListenAndServe(":8080", mux)
}"METHOD /path/{name}" en Go 1.22 y posteriores.r.PathValue("id") lee los segmentos capturados.Relacionado: Patrones de Servidores, Handlers y ServeMux HTTP - patrones de enrutamiento
Establece cabeceras antes de escribir el cuerpo; la primera Write envía las cabeceras implícitamente.
package main
import (
"net/http"
)
func main() {
http.HandleFunc("/json", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
w.Write([]byte(`{"ok":true}`))
})
http.ListenAndServe(":8080", nil)
}WriteHeader solo una vez por respuesta.Header().Set es canonizado por mayúsculas/minúsculas por net/http.http.Error para respuestas de error rápidas en texto plano.Decodifica JSON desde r.Body y siempre cierra lo que abres del lado del cliente.
package main
import (
"encoding/json"
"io"
"net/http"
)
type Payload struct {
Name string `json:"name"`
}
func main() {
http.HandleFunc("/echo", func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
var p Payload
if err := json.NewDecoder(r.Body).Decode(&p); err != nil && err != io.EOF {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
json.NewEncoder(w).Encode(p)
})
http.ListenAndServe(":8080", nil)
}r.Body debe ser leído o cerrado para reutilizar conexiones keep-alive.http.MaxBytesReader en handlers de producción.json.NewDecoder para transmitir payloads grandes.Las llamadas salientes deben usar un cliente con timeout y cancelación de contexto.
package main
import (
"context"
"fmt"
"io"
"net/http"
"time"
)
func main() {
client := &http.Client{Timeout: 5 * time.Second}
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, "https://example.com", nil)
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
b, _ := io.ReadAll(resp.Body)
fmt.Println(resp.Status, len(b))
}http.Get en servidores; usa http.DefaultClient sin timeout.defer resp.Body.Close() para devolver conexiones al pool.NewRequestWithContext vincula la llamada a la cancelación del llamador.Relacionado: Clientes HTTP, Transporte y Pooling de Conexiones - ajuste de transporte
El middleware envuelve un handler interno y ejecuta código antes o después de él.
package main
import (
"log"
"net/http"
"time"
)
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))
})
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/work", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("done"))
})
http.ListenAndServe(":8080", logging(mux))
}func(http.Handler) http.Handler.ListenAndServe, no al handler interno desnudo.Relacionado: Cadenas de Middleware y Contexto de Petición - cadenas y valores
Configura timeouts en http.Server en lugar de ListenAndServe desnudo.
package main
import (
"context"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("api"))
})
srv := &http.Server{
Addr: ":8080",
Handler: mux,
ReadHeaderTimeout: 5 * time.Second,
IdleTimeout: 60 * time.Second,
}
go func() {
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatal(err)
}
}()
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
_ = srv.Shutdown(ctx)
}ReadHeaderTimeout mitiga ataques tipo slowloris de cabeceras.Shutdown vacía las peticiones en curso durante los despliegues.main pueda manejar señales.Relacionado: Lista de Verificación de Configuración de net/http para Producción - lista completa para producción
Prueba handlers en memoria sin abrir un puerto TCP.
package main
import (
"net/http"
"net/http/httptest"
"testing"
)
func greet(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hi"))
}
func TestGreet(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/greet", nil)
rec := httptest.NewRecorder()
greet(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status=%d", rec.Code)
}
if rec.Body.String() != "hi" {
t.Fatalf("body=%q", rec.Body.String())
}
}httptest.NewRecorder implementa http.ResponseWriter y registra el estado/cuerpo.httptest.NewRequest construye un *http.Request con cuerpo opcional.Relacionado: httptest para Pruebas de Integración de Handlers - patrones de prueba más completos
Versiones de la Pila: Esta página fue escrita para Go 1.26.x (GC por defecto Green Tea, go fix modernizers - verifica el parche en la compilación), chi (última versión - verifica en la compilación), gin (última versión - verifica en la compilación), echo (última versión - verifica en la compilación), google.golang.org/grpc (última versión - verifica en la compilación), sigs.k8s.io/controller-runtime (última versión - verifica en la compilación), kubebuilder (última versión - verifica en la compilación), tinygo (última versión - verifica los objetivos de placa en la compilación), wazero (última versión - verifica en la compilación) y golangci-lint (última versión - verifica el conjunto de linters en la compilación).
Revisado por Chris St. John·Última actualización: 18 jul 2026