http.Handler-Interface
Teil des Abschnitts Objektorientierte Programmierung der GO-Journey von Coddy. Lektion 77 von 107.
Das Interface http.Handler bildet die Grundlage der Webserver-Architektur von Go. Es definiert, wie HTTP-Anfragen verarbeitet werden, und jeder Typ, der es implementiert, kann Webanfragen bedienen.
Die Schnittstelle ist bemerkenswert einfach:
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}Jeder Typ mit einer ServeHTTP-Methode kann HTTP-Anfragen verarbeiten. Hier ist ein benutzerdefinierter Handler:
type GreetHandler struct {
Greeting string
}
func (h GreetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "%s, visitor!", h.Greeting)
}Du kannst diesen Handler direkt mit einem Server verwenden:
handler := GreetHandler{Greeting: "Welcome"}
http.Handle("/greet", handler)Für einfachere Fälle stellt Go http.HandlerFunc bereit, einen Typ, mit dem du eine reguläre Funktion in einen Handler umwandeln kannst:
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello!")
}
http.Handle("/hello", http.HandlerFunc(hello))Die Leistungsfähigkeit dieser Schnittstelle wird deutlich, wenn du erkennst, dass Handler andere Handler umschließen können. Dies ermöglicht Middleware-Muster, bei denen du Protokollierung, Authentifizierung oder andere übergreifende Belange hinzufügst, ohne die ursprüngliche Handler-Logik zu verändern.
Aufgabe
EinfachLass uns ein einfaches HTTP-Handler-System erstellen, das simuliert, wie Webanfragen verarbeitet werden! Da wir in dieser Umgebung keinen tatsächlichen HTTP-Server ausführen können, erstellst du Handler, die das http.Handler-Interface implementieren, und demonstrierst, wie sie Anfragen verarbeiten, indem sie mit Mock-Anfrage-/Antwortobjekten arbeiten.
Du organisierst deinen Code über zwei Dateien:
handlers.go: Definiere deine benutzerdefinierten HTTP-Handler.Erstelle eine
MockResponseWriter-Struktur, die erfasst, was in eine HTTP-Antwort geschrieben würde. Sie sollte den Antworttext als String speichern und eineWrite(data []byte) (int, error)-Methode implementieren, die Daten an den Text anhängt. Füge eineBody() string-Methode hinzu, um die gesammelte Antwort abzurufen.Erstelle eine
MockRequest-Struktur mit den String-FeldernPathundMethod, um eine HTTP-Anfrage zu simulieren.Erstelle nun zwei Handler-Strukturen, die dem Muster des
http.Handler-Interfaces entsprechen (mit einerServeHTTP-Methode, die einen*MockResponseWriterund einen*MockRequestentgegennimmt):WelcomeHandlermit einemMessage-Feld – schreibt die Nachricht, gefolgt vom AnfragepfadMethodHandler– schreibt abhängig von der Anfragemethode unterschiedliche Antworten:"Fetching data"für GET,"Creating resource"für POST und"Method not supported"für alles andere
main.go: Verarbeite Anfragen durch deine Handler.Lies einen Handler-Typ (
welcomeodermethod) und anschließend die Details der Anfrage ein. Lies für den Welcome-Handler zusätzlich die Willkommensnachricht ein.Erstelle den passenden Handler, baue eine Mock-Anfrage auf und rufe
ServeHTTPauf, um sie zu verarbeiten. Gib den Antworttext aus.
Die folgenden Eingaben werden bereitgestellt:
- Zeile 1: Handler-Typ (
welcomeodermethod) - Zeile 2: Anfragepfad
- Zeile 3: Anfragemethode
- Zeile 4 (nur für welcome): Willkommensnachricht
Zum Beispiel bei folgender Eingabe:
welcome
/home
GET
Hello fromsollte deine Ausgabe folgendermaßen aussehen:
Hello from /homeUnd bei folgender Eingabe:
method
/api/users
POSTsollte deine Ausgabe folgendermaßen aussehen:
Creating resourceUnd bei folgender Eingabe:
method
/api/data
GETsollte deine Ausgabe folgendermaßen aussehen:
Fetching dataUnd bei folgender Eingabe:
method
/api/items
DELETEsollte deine Ausgabe folgendermaßen aussehen:
Method not supportedDiese Aufgabe veranschaulicht das grundlegende Konzept des http.Handler-Interfaces: Jeder Typ mit einer ServeHTTP-Methode kann Anfragen verarbeiten. In echten Anwendungen stammen http.ResponseWriter und *http.Request aus der Go-Standardbibliothek, aber das Muster zur Implementierung von Handlern bleibt genau gleich.
Probier es selbst
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Handler-Typ lesen
scanner.Scan()
handlerType := scanner.Text()
// Request-Pfad lesen
scanner.Scan()
path := scanner.Text()
// Request-Methode lesen
scanner.Scan()
method := scanner.Text()
// Mock-Request erstellen
request := &MockRequest{
Path: path,
Method: method,
}
// Mock-Response-Writer erstellen
response := &MockResponseWriter{}
// TODO: Basierend auf handlerType den entsprechenden Handler erstellen
// Wenn handlerType "welcome" ist, die Willkommensnachricht lesen und WelcomeHandler erstellen
// Wenn handlerType "method" ist, MethodHandler erstellen
// ServeHTTP auf dem Handler mit response und request aufrufen
if handlerType == "welcome" {
scanner.Scan()
message := scanner.Text()
// TODO: WelcomeHandler mit der Nachricht erstellen und ServeHTTP aufrufen
_ = message // Diese Zeile beim Implementieren entfernen
} else if handlerType == "method" {
// TODO: MethodHandler erstellen und ServeHTTP aufrufen
}
// Gib den Response-Body aus
fmt.Println(response.Body())
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP in Go
Externe DateienGo-Workspace & ModulePackages & ImportsExportierte vs. nicht exportierte NamenEinführung in OOP mit GoStructs als KlassenMethoden für Structs definierenPointer- vs. Value-ReceiverStruct-InitialisierungKonstruktorfunktionenRückblick – Einfacher Taschenrechner4Schnittstellen
Einführung in SchnittstellenImplizite ImplementierungSchnittstelle als VertragLeere Schnittstelle (any)TypzusicherungTypwechselZusammensetzung von SchnittstellenStringer- und Error-SchnittstellenRückblick – Formenrechner7Kapselung
Exportierte vs. nicht exportierte FelderKapselung auf PaketebeneGetter- und Setter-MethodenInformationsverbergung in GoRückblick – Studierendendatensätze10Generics (Go 1.18+)
Einführung in GenericsTypparameterTypbeschränkungenGenerische StrukturenWorkaround für generische MethodenZusammenfassung – Generische Sammlung2Typen & Structs im Detail
Grundlegende & zusammengesetzte TypenBenutzerdefinierte TypdefinitionenStruct-TagsAnonyme StructsVerschachtelte StructsNullwerte & StandardwerteRückblick – Kontaktbuch5Komposition statt Vererbung
Warum Go keine Vererbung hatGrundlagen der Struct-EinbettungMethoden-PromotionMehrere Structs einbettenEinbettung vs. AggregationVerbergen eingebetteter MethodenRückblick – Mitarbeiterhierarchie8Fehlerbehandlung & OOP
Das Error-InterfaceBenutzerdefinierte FehlertypenError-Wrapping (fmt.Errorf)Sentinel-Fehlererrors.Is() und errors.As()Panic, Defer und RecoverRückblick – Dateiparser11Standardbibliothek & OOP
io.Reader & io.Writersort.Interfacefmt.Stringer-Interfaceencoding/json mit Structshttp.Handler-InterfaceRückblick – REST-API-Modelle3Zeiger & Speicher
Grundlagen von Zeigern in GoZeiger auf StructsÜbergabe per Wert vs. ReferenzDie Funktion new()Garbage Collection in GoRückblick – Verkettete Liste erstellen6Polymorphismus in Go
Polymorphismus über InterfacesDuck-Typing in GoRegeln zur Interface-ErfüllungPolymorphe SammlungenDependency InjectionZusammenfassung – Zahlungsprozessor9Konkurrenz & OOP
Grundlagen der GoroutinesChannels & KommunikationGepufferte vs. ungepufferte ChannelsSelect-Anweisungsync.Mutex & sync.RWMutexsync.WaitGroupThread-sicheres Struct-DesignRückblick – Worker PoolÜbe selbstständig: Online-Go-Compiler