L'interface http.Handler
Fait partie de la section Programmation Orientée Objet du Journey GO de Coddy — leçon 77 sur 107.
L'interface http.Handler est le fondement de l'architecture du serveur web de Go. Elle définit la manière dont les requêtes HTTP sont traitées, et tout type l'implémentant peut répondre à des requêtes web.
L'interface est remarquablement simple :
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}Tout type possédant une méthode ServeHTTP peut gérer des requêtes HTTP. Voici un gestionnaire personnalisé :
type GreetHandler struct {
Greeting string
}
func (h GreetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "%s, visitor!", h.Greeting)
}Vous pouvez utiliser ce gestionnaire directement avec un serveur :
handler := GreetHandler{Greeting: "Welcome"}
http.Handle("/greet", handler)Pour des cas plus simples, Go fournit http.HandlerFunc, un type qui vous permet de convertir une fonction classique en un gestionnaire :
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello!")
}
http.Handle("/hello", http.HandlerFunc(hello))La puissance de cette interface devient évidente lorsque vous réalisez que les gestionnaires peuvent envelopper d'autres gestionnaires. Cela permet des modèles de middleware où vous ajoutez la journalisation, l'authentification ou d'autres préoccupations transversales sans modifier la logique du gestionnaire d'origine.
Défi
FacileConstruisons un système simple de gestionnaire HTTP qui simule la manière dont les requêtes web sont traitées ! Comme nous ne pouvons pas exécuter un véritable serveur HTTP dans cet environnement, vous allez créer des gestionnaires qui implémentent l'interface http.Handler et démontrer comment ils traitent les requêtes en travaillant avec des objets de requête/réponse fictifs (mock).
Vous organiserez votre code sur deux fichiers :
handlers.go: Définissez vos gestionnaires HTTP personnalisés.Créez une structure
MockResponseWriterqui capture ce qui serait écrit dans une réponse HTTP. Elle doit stocker le corps de la réponse sous forme de chaîne de caractères et implémenter une méthodeWrite(data []byte) (int, error)qui ajoute les données au corps. Ajoutez une méthodeBody() stringpour récupérer la réponse accumulée.Créez une structure
MockRequestavec des champs de type chaînePathetMethodpour simuler une requête HTTP.Créez maintenant deux structures de gestionnaire qui implémentent le modèle de l'interface
http.Handler(avec une méthodeServeHTTPqui prend un*MockResponseWriteret un*MockRequest) :WelcomeHandleravec un champMessage- écrit le message suivi du chemin de la requêteMethodHandler- écrit différentes réponses basées sur la méthode de la requête :"Fetching data"pour GET,"Creating resource"pour POST, et"Method not supported"pour tout le reste
main.go: Traitez les requêtes via vos gestionnaires.Lisez un type de gestionnaire (
welcomeoumethod), puis lisez les détails de la requête. Pour le gestionnaire welcome, lisez également le message de bienvenue.Créez le gestionnaire approprié, construisez une requête fictive et appelez
ServeHTTPpour la traiter. Affichez le corps de la réponse.
Les entrées suivantes seront fournies :
- Ligne 1 : Type de gestionnaire (
welcomeoumethod) - Ligne 2 : Chemin de la requête
- Ligne 3 : Méthode de la requête
- Ligne 4 (uniquement pour welcome) : Message de bienvenue
Par exemple, avec :
welcome
/home
GET
Hello fromVotre sortie devrait être :
Hello from /homeEt avec :
method
/api/users
POSTVotre sortie devrait être :
Creating resourceEt avec :
method
/api/data
GETVotre sortie devrait être :
Fetching dataEt avec :
method
/api/items
DELETEVotre sortie devrait être :
Method not supportedCe défi démontre le concept central de l'interface http.Handler — n'importe quel type possédant une méthode ServeHTTP peut gérer des requêtes. Dans les applications réelles, le http.ResponseWriter et le *http.Request proviennent de la bibliothèque standard de Go, mais le modèle d'implémentation des gestionnaires reste exactement le même.
Aide-mémoire
L'interface http.Handler est le fondement de l'architecture du serveur web de Go :
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}Tout type possédant une méthode ServeHTTP peut gérer des requêtes HTTP :
type GreetHandler struct {
Greeting string
}
func (h GreetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "%s, visitor!", h.Greeting)
}Enregistrez un gestionnaire auprès du serveur :
handler := GreetHandler{Greeting: "Welcome"}
http.Handle("/greet", handler)Pour les cas plus simples, utilisez http.HandlerFunc pour convertir une fonction en un gestionnaire :
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello!")
}
http.Handle("/hello", http.HandlerFunc(hello))Les gestionnaires peuvent envelopper d'autres gestionnaires, permettant des modèles de middleware pour la journalisation, l'authentification ou d'autres préoccupations transversales.
Essayez vous-même
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Lire le type de gestionnaire
scanner.Scan()
handlerType := scanner.Text()
// Lire le chemin de la requête
scanner.Scan()
path := scanner.Text()
// Lire la méthode de la requête
scanner.Scan()
method := scanner.Text()
// Créer une simulation de requête
request := &MockRequest{
Path: path,
Method: method,
}
// Créer une simulation de rédacteur de réponse
response := &MockResponseWriter{}
// TODO: En fonction de handlerType, créer le gestionnaire approprié
// Si handlerType est "welcome", lire le message de bienvenue et créer WelcomeHandler
// Si handlerType est "method", créer MethodHandler
// Appeler ServeHTTP sur le gestionnaire avec response et request
if handlerType == "welcome" {
scanner.Scan()
message := scanner.Text()
// TODO: Créer WelcomeHandler avec le message et appeler ServeHTTP
_ = message // Supprimer cette ligne lors de l'implémentation
} else if handlerType == "method" {
// TODO: Créer MethodHandler et appeler ServeHTTP
}
// Afficher le corps de la réponse
fmt.Println(response.Body())
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Fondamentaux de la POO en Go
Fichiers externesEspace de travail et Modules GoPackages et ImportsNoms exportés vs non exportésIntroduction à la POO en GoLes Structs comme ClassesDéfinir des méthodes sur les StructsReceveurs par pointeur vs par valeurInitialisation de StructsFonctions constructeursRécapitulatif - Calculatrice simple4Interfaces
Introduction aux interfacesImplémentation impliciteL'interface comme contratInterface vide (any)Assertion de typeType SwitchComposition d'interfacesInterfaces Stringer & ErrorRécapitulatif - Calculateur de formes7Encapsulation
Champs exportés vs non exportésEncapsulation au niveau du packageMéthodes Getter & SetterMasquage d'informations en GoRécapitulatif - Dossiers étudiants10Génériques (Go 1.18+)
Introduction aux génériquesParamètres de typeContraintes de typeStructures génériquesContournement pour les méthodes génériquesRécapitulatif - Collections génériques13Patrons de conception, Partie 1
Introduction aux Design PatternsPatron SingletonPatron FactoryPatron Abstract FactoryPatron ObserverPatron Strategy2Exploration approfondie des Types et Structs
Types de base et compositesDéfinitions de types personnalisésTags de StructStructs anonymesStructs imbriquéesValeurs par défaut et Zero ValuesRécapitulatif - Carnet de contacts5Composition plutôt qu'héritage
Pourquoi Go n'a pas d'héritageLes bases de l'imbrication de structsPromotion de méthodesImbriquer plusieurs structsImbrication vs AgrégationMasquage de méthodes imbriquéesRécapitulatif - Hiérarchie des employés8Gestion des erreurs & POO
L'interface errorTypes d'erreurs personnalisésError Wrapping (fmt.Errorf)Erreurs sentinelleserrors.Is() et errors.As()Panic, Defer et RecoverRécapitulatif - File Parser11Bibliothèque standard et POO
io.Reader & io.WriterL'interface sort.InterfaceL'interface fmt.Stringerencoding/json avec les StructsL'interface http.HandlerRécapitulatif - Modèles d'API REST14Patrons de conception, Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Template MethodPatron ÉtatPatron CompositeMiddleware en tant que Décorateur3Pointeurs et Mémoire
Bases des pointeurs en GoPointeurs vers des structsPassage par valeur vs référenceLa fonction new()Garbage Collection en GoRécapitulatif - Constructeur de liste chaînée6Le polymorphisme en Go
Le polymorphisme via les interfacesLe Duck Typing en GoRègles de satisfaction des interfacesCollections polymorphesInjection de dépendancesRécapitulatif - Processeur de paiement9Concurrence et POO
Bases des GoroutinesChannels et CommunicationChannels avec buffer vs sans bufferL'instruction Selectsync.Mutex et sync.RWMutexsync.WaitGroupConception de structures Thread-SafeRécapitulatif - Worker Pool