En aquest tema, aprendrem què és el middleware en el context del desenvolupament web amb Go, com crear i utilitzar middleware, i veurem alguns exemples pràctics. El middleware és una part essencial de moltes aplicacions web, ja que permet la manipulació de sol·licituds i respostes de manera modular i reutilitzable.
Què és el Middleware?
El middleware és un component que s'interposa en el flux de sol·licituds i respostes d'una aplicació web. Permet processar les sol·licituds abans que arribin als controladors finals i manipular les respostes abans que es retornin als clients. Alguns usos comuns del middleware inclouen:
- Autenticació i autorització
- Registre de sol·licituds
- Gestió d'errors
- Compressió de respostes
- Caching
Creació de Middleware en Go
En Go, el middleware es pot implementar com una funció que rep un http.Handler i retorna un altre http.Handler. Aquesta funció pot realitzar operacions abans i després de cridar al següent http.Handler en la cadena.
Exemple Bàsic de Middleware
A continuació, es mostra un exemple bàsic de middleware que registra les sol·licituds entrants:
package main
import (
"fmt"
"log"
"net/http"
"time"
)
// Middleware de registre
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
log.Printf("Iniciant sol·licitud %s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
log.Printf("Sol·licitud %s %s completada en %s", r.Method, r.URL.Path, time.Since(start))
})
}
func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hola, món!")
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", helloHandler)
// Aplicar el middleware
loggedMux := loggingMiddleware(mux)
log.Println("Servidor escoltant en el port 8080")
http.ListenAndServe(":8080", loggedMux)
}Explicació del Codi
- Funció
loggingMiddleware: Aquesta funció rep unhttp.Handler(next) i retorna un nouhttp.Handlerque registra la sol·licitud abans i després de cridar anext.ServeHTTP(w, r). - Funció
helloHandler: Un controlador simple que respon amb "Hola, món!". - Funció
main: Es crea unServeMuxper gestionar les rutes, s'aplica el middleware de registre i es comença a escoltar en el port 8080.
Middleware Multiples
És comú utilitzar múltiples middleware en una aplicació. A continuació, es mostra com es poden encadenar diversos middleware:
package main
import (
"fmt"
"log"
"net/http"
"time"
)
// Middleware de registre
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
log.Printf("Iniciant sol·licitud %s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
log.Printf("Sol·licitud %s %s completada en %s", r.Method, r.URL.Path, time.Since(start))
})
}
// Middleware d'autenticació
func authMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Authorization") != "Bearer token" {
http.Error(w, "No autoritzat", http.StatusUnauthorized)
return
}
next.ServeHTTP(w, r)
})
}
func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hola, món!")
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", helloHandler)
// Aplicar múltiples middleware
handler := loggingMiddleware(authMiddleware(mux))
log.Println("Servidor escoltant en el port 8080")
http.ListenAndServe(":8080", handler)
}Explicació del Codi
- Funció
authMiddleware: Aquest middleware comprova si la sol·licitud té un encapçalament d'autorització vàlid. Si no és així, retorna un error 401. - Encadenament de Middleware: En la funció
main, els middleware es poden encadenar aplicant-los successivament.
Exercicis Pràctics
Exercici 1: Middleware de Compressió
Implementa un middleware que comprimeixi les respostes utilitzant gzip.
Exercici 2: Middleware de Caching
Implementa un middleware que emmagatzemi en memòria cau les respostes per a sol·licituds GET.
Solucions
Solució Exercici 1
package main
import (
"compress/gzip"
"fmt"
"log"
"net/http"
"strings"
)
// Middleware de compressió
func gzipMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
next.ServeHTTP(w, r)
return
}
w.Header().Set("Content-Encoding", "gzip")
gz := gzip.NewWriter(w)
defer gz.Close()
gzrw := gzipResponseWriter{Writer: gz, ResponseWriter: w}
next.ServeHTTP(gzrw, r)
})
}
type gzipResponseWriter struct {
http.ResponseWriter
Writer *gzip.Writer
}
func (w gzipResponseWriter) Write(b []byte) (int, error) {
return w.Writer.Write(b)
}
func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hola, món!")
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", helloHandler)
// Aplicar el middleware de compressió
handler := gzipMiddleware(mux)
log.Println("Servidor escoltant en el port 8080")
http.ListenAndServe(":8080", handler)
}Solució Exercici 2
package main
import (
"fmt"
"log"
"net/http"
"sync"
"time"
)
// Middleware de caching
func cacheMiddleware(next http.Handler) http.Handler {
cache := make(map[string]string)
var mu sync.Mutex
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
next.ServeHTTP(w, r)
return
}
mu.Lock()
if response, found := cache[r.URL.Path]; found {
mu.Unlock()
fmt.Fprintln(w, response)
return
}
mu.Unlock()
rw := &responseWriter{ResponseWriter: w}
next.ServeHTTP(rw, r)
mu.Lock()
cache[r.URL.Path] = rw.body
mu.Unlock()
})
}
type responseWriter struct {
http.ResponseWriter
body string
}
func (rw *responseWriter) Write(b []byte) (int, error) {
rw.body = string(b)
return rw.ResponseWriter.Write(b)
}
func helloHandler(w http.ResponseWriter, r *http.Request) {
time.Sleep(2 * time.Second) // Simular una operació costosa
fmt.Fprintln(w, "Hola, món!")
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", helloHandler)
// Aplicar el middleware de caching
handler := cacheMiddleware(mux)
log.Println("Servidor escoltant en el port 8080")
http.ListenAndServe(":8080", handler)
}Conclusió
El middleware és una eina poderosa per modularitzar i reutilitzar la lògica comuna en les aplicacions web. En aquest tema, hem après què és el middleware, com crear-lo i utilitzar-lo, i hem vist exemples pràctics de middleware de registre, autenticació, compressió i caching. Amb aquests coneixements, estàs preparat per implementar middleware personalitzat en les teves aplicacions Go.
Curs de Programació en Go
Mòdul 1: Introducció a Go
- Introducció a Go
- Configuració de l'Entorn Go
- El Teu Primer Programa en Go
- Sintaxi i Estructura Bàsiques
Mòdul 2: Conceptes Bàsics
Mòdul 3: Estructures de Dades Avançades
Mòdul 4: Gestió d'Errors
Mòdul 5: Concurrència
Mòdul 6: Temes Avançats
Mòdul 7: Desenvolupament Web amb Go
Mòdul 8: Treballant amb Bases de Dades
Mòdul 9: Desplegament i Manteniment
- Construcció i Desplegament d'Aplicacions Go
- Registre
- Monitorització i Optimització del Rendiment
- Millors Pràctiques de Seguretat
