Interfaccia http.Handler
Fa parte della sezione Programmazione orientata agli oggetti del percorso GO di Coddy. Lezione 77 di 107.
L'interfaccia http.Handler è il fondamento dell'architettura del server web di Go. Definisce come vengono elaborate le richieste HTTP e qualsiasi tipo che la implementi può gestire richieste web.
L'interfaccia è straordinariamente semplice:
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}Qualsiasi tipo con un metodo ServeHTTP può gestire richieste HTTP. Ecco un handler personalizzato:
type GreetHandler struct {
Greeting string
}
func (h GreetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "%s, visitor!", h.Greeting)
}Puoi usare questo gestore direttamente con un server:
handler := GreetHandler{Greeting: "Welcome"}
http.Handle("/greet", handler)Per i casi più semplici, Go fornisce http.HandlerFunc, un tipo che ti permette di convertire una funzione normale in un gestore:
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello!")
}
http.Handle("/hello", http.HandlerFunc(hello))La potenza di questa interfaccia diventa evidente quando ti rendi conto che gli handler possono avvolgere altri handler. Questo consente di adottare schemi middleware in cui aggiungi registrazione, autenticazione o altri aspetti trasversali senza modificare la logica originale degli handler.
Sfida
FacileCreiamo un semplice sistema di gestori HTTP che simula come vengono elaborate le richieste web! Poiché in questo ambiente non possiamo eseguire un vero server HTTP, creerai dei gestori che implementano l’interfaccia http.Handler e mostrerai come elaborano le richieste lavorando con oggetti di richiesta/risposta simulati.
Organizzerai il codice in due file:
handlers.go: definisci i tuoi gestori HTTP personalizzati.Crea una struct
MockResponseWriterche acquisisce ciò che verrebbe scritto in una risposta HTTP. Dovrebbe memorizzare il corpo della risposta come stringa e implementare un metodoWrite(data []byte) (int, error)che aggiunge i dati al corpo. Aggiungi un metodoBody() stringper recuperare la risposta accumulata.Crea una struct
MockRequestcon i campi stringaPatheMethodper simulare una richiesta HTTP.Ora crea due struct gestore che implementano il modello dell’interfaccia
http.Handler(con un metodoServeHTTPche accetta*MockResponseWritere*MockRequest):WelcomeHandlercon un campoMessage: scrive il messaggio seguito dal percorso della richiestaMethodHandler: scrive risposte diverse in base al metodo della richiesta:"Fetching data"per GET,"Creating resource"per POST e"Method not supported"per qualsiasi altro metodo
main.go: elabora le richieste tramite i tuoi gestori.Leggi un tipo di gestore (
welcomeomethod), poi leggi i dettagli della richiesta. Per il gestore di benvenuto, leggi anche il messaggio di benvenuto.Crea il gestore appropriato, costruisci una richiesta simulata e chiama
ServeHTTPper elaborarla. Stampa il corpo della risposta.
Verranno forniti i seguenti input:
- Riga 1: tipo di gestore (
welcomeomethod) - Riga 2: percorso della richiesta
- Riga 3: metodo della richiesta
- Riga 4 (solo per welcome): messaggio di benvenuto
Per esempio, dato:
welcome
/home
GET
Hello fromIl tuo output dovrebbe essere:
Hello from /homeE dato:
method
/api/users
POSTIl tuo output dovrebbe essere:
Creating resourceE dato:
method
/api/data
GETIl tuo output dovrebbe essere:
Fetching dataE dato:
method
/api/items
DELETEIl tuo output dovrebbe essere:
Method not supportedQuesta sfida illustra il concetto fondamentale dell’interfaccia http.Handler: qualsiasi tipo con un metodo ServeHTTP può gestire le richieste. Nelle applicazioni reali, http.ResponseWriter e *http.Request provengono dalla libreria standard di Go, ma il modello per implementare i gestori rimane esattamente lo stesso.
Provalo tu
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Leggi il tipo di handler
scanner.Scan()
handlerType := scanner.Text()
// Leggi il percorso della richiesta
scanner.Scan()
path := scanner.Text()
// Leggi il metodo della richiesta
scanner.Scan()
method := scanner.Text()
// Crea una richiesta simulata
request := &MockRequest{
Path: path,
Method: method,
}
// Crea un writer di risposta simulato
response := &MockResponseWriter{}
// TODO: In base a handlerType, crea l'handler appropriato
// Se handlerType è "welcome", leggi il messaggio di benvenuto e crea WelcomeHandler
// Se handlerType è "method", crea MethodHandler
// Chiama ServeHTTP sull'handler con response e request
if handlerType == "welcome" {
scanner.Scan()
message := scanner.Text()
// TODO: Crea WelcomeHandler con il messaggio e chiama ServeHTTP
_ = message // Rimuovi questa riga durante l'implementazione
} else if handlerType == "method" {
// TODO: Crea MethodHandler e chiama ServeHTTP
}
// Stampa il corpo della risposta
fmt.Println(response.Body())
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti di OOP in Go
File esterniWorkspace e moduli GoPacchetti e importazioniNomi esportati e non esportatiIntroduzione all’OOP in GoGli struct come classiDefinire metodi sugli structReceiver con puntatore vs receiver con valoreInizializzazione degli structFunzioni costruttriciRiepilogo - Calcolatrice semplice4Interfacce
Introduzione alle interfacceImplementazione implicitaL’interfaccia come contrattoInterfaccia vuota (any)Asserzione di tipoSwitch sul tipoComposizione di interfacceInterfacce Stringer ed ErrorRipasso - Calcolatore di forme7Incapsulamento
Campi esportati e non esportatiIncapsulamento a livello di packageMetodi Getter e SetterNascondimento delle informazioni in GoRiepilogo - Registri degli studenti10Tipi generici (Go 1.18+)
Introduzione ai tipi genericiParametri di tipoVincoli di tipoStruct genericheSoluzione alternativa per i metodi genericiRiepilogo - Collezione generica13Modelli di progettazione Parte 1
Introduzione ai modelli di progettazioneModello SingletonModello FactoryModello Abstract FactoryModello ObserverModello Strategy2Approfondimento su tipi e struct
Tipi di base e compostiDefinizioni di tipi personalizzatiTag delle structStruct anonimeStruct annidateValori zero e predefinitiRipasso - Rubrica5Composizione invece dell'ereditarietà
Perché Go non ha l'ereditarietàFondamenti dell'embedding delle structPromozione dei metodiEmbedding di più structEmbedding e aggregazione a confrontoMascheramento dei metodi embeddedRiepilogo: gerarchia dei dipendenti8Gestione degli errori e OOP
L'interfaccia errorTipi di errore personalizzatiWrapping degli errori (fmt.Errorf)Errori sentinellaerrors.Is() ed errors.As()Panic, Defer e RecoverRiepilogo - Parser di file11Libreria standard e OOP
io.Reader e io.Writersort.InterfaceInterfaccia fmt.Stringerencoding/json con le structInterfaccia http.HandlerRipasso - modelli REST API14Modelli di progettazione – Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositeMiddleware come Decorator3Puntatori e memoria
Concetti base dei puntatori in GoPuntatori a structPassaggio per valore vs per riferimentoLa funzione new()Garbage collection in GoRiepilogo - Costruttore di liste concatenate6Polimorfismo in Go
Polimorfismo tramite interfacceDuck typing in GoRegole di soddisfacimento delle interfacceCollezioni polimorficheIniezione delle dipendenzeRiepilogo - Elaboratore di pagamenti9Concorrenza e OOP
Basi delle goroutineCanali e comunicazioneCanali bufferizzati vs non bufferizzatiIstruzione selectsync.Mutex e sync.RWMutexsync.WaitGroupProgettazione di struct thread-safeRiepilogo: worker poolEsercitati da solo: Compilatore Go online