El paquete net/http
de Go es una herramienta fundamental para desarrolladores que buscan crear servidores y clientes HTTP eficientes. Este paquete forma parte de la biblioteca estándar de Go y ofrece una amplia gama de funcionalidades para manejar comunicaciones HTTP de manera efectiva. A continuación, exploraremos en profundidad cómo utilizar el paquete net/http
para construir aplicaciones web sólidas y escalables.
Introducción al paquete net/http
El paquete net/http
proporciona las capacidades necesarias para:
- Crear servidores HTTP.
- Desarrollar clientes HTTP.
- Manipular solicitudes y respuestas HTTP.
- Implementar middleware y manejadores personalizados.
Al ser parte de la biblioteca estándar, no es necesario instalar dependencias externas para comenzar a utilizarlo.
Creación de un servidor HTTP básico
Para iniciar un servidor web en Go, se puede utilizar la función http.ListenAndServe
. A continuación se muestra un ejemplo básico:
package main
import (
"fmt"
"net/http"
)
func manejadorSaludo(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "¡Bienvenido al servidor HTTP en Go!")
}
func main() {
http.HandleFunc("/", manejadorSaludo)
if err := http.ListenAndServe(":8080", nil); err != nil {
fmt.Println("Error al iniciar el servidor:", err)
}
}
Este código inicia un servidor que escucha en el puerto 8080 y responde con un mensaje de bienvenida a cualquier solicitud entrante.
Manejo de solicitudes y respuestas
El paquete net/http
utiliza las estructuras http.Request
y http.ResponseWriter
para representar solicitudes y respuestas HTTP respectivamente.
Estructura de http.Request
La estructura http.Request
contiene información sobre la solicitud entrante, como:
- Método HTTP (GET, POST, etc.).
- URL solicitada.
- Encabezados y cookies.
- Cuerpo de la solicitud.
Uso de http.ResponseWriter
El http.ResponseWriter
permite enviar respuestas al cliente. Se puede escribir directamente en él para enviar el cuerpo de la respuesta y establecer encabezados HTTP.
func manejadorDatos(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"mensaje": "Datos procesados correctamente"}`))
}
Rutas y enrutamiento
Aunque el paquete net/http
no incluye un enrutador sofisticado, permite asociar manejadores a rutas específicas usando http.HandleFunc
o http.Handle
.
http.HandleFunc("/usuarios", manejadorUsuarios)
http.HandleFunc("/productos", manejadorProductos)
Para aplicaciones más complejas, es común utilizar enrutadores externos, pero es posible implementar enrutamiento básico con las herramientas estándar.
Manejadores personalizados y la interfaz http.Handler
Un manejador en Go es cualquier objeto que implemente la interfaz http.Handler
, es decir, que tenga un método ServeHTTP
.
type miManejador struct{}
func (h *miManejador) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Este es un manejador personalizado utilizando http.Handler")
}
func main() {
manejador := &miManejador{}
http.Handle("/personalizado", manejador)
http.ListenAndServe(":8080", nil)
}
Este enfoque permite mayor flexibilidad y reutilización de código en aplicaciones de gran escala.
Middleware y composición de manejadores
Los middleware son componentes que se ejecutan antes o después de los manejadores principales, permitiendo agregar funcionalidades transversales como autenticación, registro de solicitudes o manejo de errores.
func registroMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Println("Solicitud recibida:", r.URL.Path)
next.ServeHTTP(w, r)
})
}
func manejadorPrincipal(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Respuesta del manejador principal")
}
func main() {
http.Handle("/", registroMiddleware(http.HandlerFunc(manejadorPrincipal)))
http.ListenAndServe(":8080", nil)
}
Servir archivos estáticos
Para servir archivos estáticos, como archivos HTML, CSS o imágenes, se utiliza http.FileServer
.
func main() {
fs := http.FileServer(http.Dir("./public"))
http.Handle("/static/", http.StripPrefix("/static/", fs))
http.ListenAndServe(":8080", nil)
}
Este código sirve los archivos ubicados en el directorio public
bajo la ruta /static/
.
Manejando parámetros de consulta y formularios
Parámetros de consulta
Los parámetros de consulta en la URL pueden obtenerse a través de r.URL.Query()
.
func manejadorConsulta(w http.ResponseWriter, r *http.Request) {
valores := r.URL.Query()
id := valores.Get("id")
fmt.Fprintf(w, "El ID proporcionado es: %s", id)
}
Procesamiento de formularios
Para procesar datos enviados mediante formularios (método POST), se utiliza r.ParseForm()
.
func manejadorFormulario(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
http.Error(w, "Error al procesar el formulario", http.StatusBadRequest)
return
}
nombre := r.FormValue("nombre")
correo := r.FormValue("correo")
fmt.Fprintf(w, "Nombre: %s, Correo: %s", nombre, correo)
}
Subida de archivos al servidor
El manejo de archivos enviados desde formularios se realiza mediante r.FormFile
.
func manejadorSubida(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Método no permitido", http.StatusMethodNotAllowed)
return
}
archivo, encabezado, err := r.FormFile("archivo")
if err != nil {
http.Error(w, "Error al obtener el archivo", http.StatusBadRequest)
return
}
defer archivo.Close()
// Procesar el archivo (por ejemplo, guardarlo en el servidor)
rutaDestino := "./uploads/" + encabezado.Filename
ficheroDestino, err := os.Create(rutaDestino)
if err != nil {
http.Error(w, "Error al guardar el archivo", http.StatusInternalServerError)
return
}
defer ficheroDestino.Close()
io.Copy(ficheroDestino, archivo)
fmt.Fprintf(w, "Archivo subido exitosamente: %s", encabezado.Filename)
}
Implementación de clientes HTTP
Además de crear servidores, el paquete net/http
permite realizar solicitudes HTTP como cliente.
func realizarSolicitud() {
resp, err := http.Get("https://api.ejemplo.com/datos")
if err != nil {
fmt.Println("Error en la solicitud:", err)
return
}
defer resp.Body.Close()
cuerpo, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error al leer la respuesta:", err)
return
}
fmt.Println("Respuesta del servidor:", string(cuerpo))
}
Para solicitudes más complejas, se puede utilizar http.Client
y construir solicitudes con http.NewRequest
.
Configuración de tiempo de espera y transporte
Es posible establecer configuraciones personalizadas en el cliente HTTP, como tiempos de espera y proxies.
func clientePersonalizado() {
transport := &http.Transport{
Proxy: http.ProxyFromEnvironment,
}
client := &http.Client{
Transport: transport,
Timeout: 30 * time.Second,
}
req, err := http.NewRequest("GET", "https://api.ejemplo.com/datos", nil)
if err != nil {
fmt.Println("Error al crear la solicitud:", err)
return
}
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error en la solicitud:", err)
return
}
defer resp.Body.Close()
// Procesar la respuesta
}
Uso de contexto para cancelación y plazos
El uso del paquete context
permite manejar cancelaciones y plazos de tiempo en solicitudes.
func solicitudConContexto() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.ejemplo.com/lento", nil)
if err != nil {
fmt.Println("Error al crear la solicitud:", err)
return
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
fmt.Println("Error en la solicitud:", err)
return
}
defer resp.Body.Close()
// Procesar la respuesta
}
Implementación de HTTPS y manejo de certificados
Para servir contenido sobre HTTPS, se utilizan las funciones ListenAndServeTLS
y se proporcionan los certificados SSL.
func main() {
http.HandleFunc("/", manejadorSeguro)
if err := http.ListenAndServeTLS(":8443", "cert.pem", "key.pem", nil); err != nil {
fmt.Println("Error al iniciar el servidor HTTPS:", err)
}
}
Es importante gestionar correctamente los certificados y asegurar las conexiones para proteger la información transmitida.
Mejoras de rendimiento con HTTP/2
El soporte para HTTP/2 en Go es automático cuando se sirve sobre TLS usando ListenAndServeTLS
. HTTP/2 mejora el rendimiento mediante multiplexación de solicitudes y reducción de latencia.
Consejos de seguridad en aplicaciones web
Al desarrollar aplicaciones web, es crucial seguir prácticas de seguridad para proteger el servicio y a los usuarios.
Validación y saneamiento de entradas
Siempre validar y sanear los datos recibidos de los usuarios para prevenir inyecciones y otros ataques.
import "html"
func manejadorSeguro(w http.ResponseWriter, r *http.Request) {
entrada := r.FormValue("entrada")
entradaSegura := html.EscapeString(entrada)
fmt.Fprintf(w, "Entrada segura: %s", entradaSegura)
}
Uso de encabezados de seguridad
Establecer encabezados que indiquen a los navegadores cómo manejar el contenido.
func seguridadMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Strict-Transport-Se
Lecciones de este módulo
Explora todas las lecciones disponibles en Comunicación por HTTP
Explora más sobre Go
Descubre más recursos de Go

Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Go es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.