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 des serveurs web de Go. Elle définit la manière dont les requêtes HTTP sont traitées, et tout type qui l’implémente peut répondre aux requêtes web.
L’interface est remarquablement simple :
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}Tout type doté d’une méthode ServeHTTP peut traiter les 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 les cas plus simples, Go fournit http.HandlerFunc, un type qui vous permet de convertir une fonction ordinaire en 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 encapsuler d’autres gestionnaires. Cela permet d’utiliser des modèles de middleware dans lesquels 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 gestionnaires HTTP qui simule le traitement des requêtes web ! 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 montrer comment ils traitent les requêtes en travaillant avec des objets de requête/réponse simulés.
Vous allez organiser 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 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înePathetMethodafin de simuler une requête HTTP.Créez maintenant deux structures de gestionnaires 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 selon la méthode de la requête :"Fetching data"pour GET,"Creating resource"pour POST, et"Method not supported"pour toute autre méthode
main.go: traitez les requêtes avec 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 simulée 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 doit être :
Hello from /homeEt avec :
method
/api/users
POSTVotre sortie doit être :
Creating resourceEt avec :
method
/api/data
GETVotre sortie doit être :
Fetching dataEt avec :
method
/api/items
DELETEVotre sortie doit être :
Method not supportedCe défi présente le concept fondamental de l’interface http.Handler : tout type possédant une méthode ServeHTTP peut traiter des requêtes. Dans les applications réelles, http.ResponseWriter et *http.Request proviennent de la bibliothèque standard de Go, mais le modèle d’implémentation des gestionnaires reste exactement le même.
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 requête mock
request := &MockRequest{
Path: path,
Method: method,
}
// Créer un mock response writer
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
}
// Affiche 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 et non exportésIntroduction à la POO en GoStructs comme classesDéfinir des méthodes sur des structsRécepteurs pointeurs ou par valeurInitialisation des structsFonctions constructeursRécapitulatif - Calculatrice simple4Interfaces
Introduction aux interfacesImplémentation impliciteL’interface comme contratInterface vide (any)Assertion de typeCommutation de typeComposition d’interfacesInterfaces Stringer et ErrorRécapitulatif - Calculateur de formes7Encapsulation
Champs exportés vs non exportésEncapsulation au niveau du packageMéthodes Getter et SetterDissimulation de l’information en GoRécapitulatif – Fiches d’étudiants10Génériques (Go 1.18+)
Introduction aux génériquesParamètres de typeContraintes de typeStructures génériquesSolution de contournement pour les méthodes génériquesRécapitulatif - Collection générique2Plongée approfondie dans les types et les structs
Types de base et compositesDéfinitions de types personnalisésTags de structStructs anonymesStructs imbriquésValeurs zéro et valeurs par défautRécapitulatif - Carnet de contacts5La composition plutôt que l’héritage
Pourquoi Go n’a pas d’héritageBases de l’inclusion de structsPromotion des méthodesInclure plusieurs structsInclusion ou agrégationMasquage des méthodes inclusesRécapitulatif : hiérarchie des employés8Gestion des erreurs et POO
L’interface errorTypes d’erreurs personnalisésEnrobage des erreurs (fmt.Errorf)Erreurs sentinelleserrors.Is() et errors.As()Panic, Defer et RecoverRécapitulatif - Analyseur de fichiers11Bibliothèque standard et POO
io.Reader et io.Writersort.InterfaceInterface fmt.Stringerencoding/json avec des structsInterface http.HandlerRécapitulatif - Modèles d’API REST14Modèles de conception – Partie 2
Modèle CommandeModèle AdaptateurModèle DécorateurModèle Méthode modèleModèle ÉtatModèle CompositeMiddleware comme décorateur3Pointeurs et mémoire
Notions de base des pointeurs en GoPointeurs vers des structuresPassage par valeur ou par référenceLa fonction new()Garbage collection en GoRécapitulatif - Constructeur de listes chaînées6Polymorphisme en Go
Polymorphisme via les interfacesDuck typing en GoRègles de satisfaction des interfacesCollections polymorphesInjection de dépendancesRécapitulatif – Processeur de paiements9Concurrence et POO
Bases des GoroutinesCanaux et communicationCanaux tamponnés ou non tamponnésInstruction selectsync.Mutex et sync.RWMutexsync.WaitGroupConception de structures thread-safeRécapitulatif - Pool de workersEntraînez-vous par vous-même : Compilateur Go en ligne