Go's http.ServeMux ist alles, was Sie brauchen
Wenhao Wang
Dev Intern · Leapcell

Optimierung und Anwendungsanalyse von http.ServeMux in der Go 1.22 Standardbibliothek
Im Bereich der Go-Webentwicklung wählen viele Entwickler die Einführung von Drittanbieterbibliotheken wie httprouter und gorilla/mux, um effizientere und flexiblere Routing-Funktionen zu erzielen. In der Go-Version 1.22 hat das offizielle jedoch die http.ServeMux in der Standardbibliothek erheblich optimiert. Es wird erwartet, dass dieser Schritt die Abhängigkeit der Entwickler von Routing-Bibliotheken von Drittanbietern verringert.
I. Highlights von Go 1.22: Verbesserte Mustererkennungsfähigkeit
Die Go-Version 1.22 hat einen lang erwarteten Vorschlag zur Verbesserung der Mustererkennungsfähigkeit des Standard-HTTP-Service-Multiplexers im net/http-Paket der Standardbibliothek implementiert. Der vorhandene Multiplexer (http.ServeMux) kann nur grundlegende Pfadvergleichsfunktionen bereitstellen, die relativ begrenzt sind. Dies hat zur Entstehung einer grossen Anzahl von Bibliotheken von Drittanbietern geführt, um die Anforderungen der Entwickler an leistungsfähigere Routing-Funktionen zu erfüllen. Der neue Multiplexer in Go 1.22 wird die funktionale Lücke zu Bibliotheken von Drittanbietern durch die Einführung fortschrittlicher Matching-Funktionen erheblich verringern. Dieser Artikel stellt kurz den neuen Multiplexer (mux) vor, gibt ein Beispiel für einen REST-Server und vergleicht die Leistung des neuen Standardbibliotheks-Mux mit der von gorilla/mux.
II. Verwendung des neuen Mux
Für Go-Entwickler, die Erfahrung mit der Verwendung von Mux/Routern von Drittanbietern (z. B. gorilla/mux) haben, ist die Verwendung des neuen Standard-Mux eine einfache und vertraute Aufgabe. Es wird empfohlen, dass Entwickler zuerst die offizielle Dokumentation lesen, die prägnant und klar ist.
(I) Grundlegendes Verwendungsbeispiel
Der folgende Code demonstriert einige neue Mustererkennungsfunktionen von mux:
package main import ( "fmt" "net/http" ) func main() { mux := http.NewServeMux() mux.HandleFunc("GET /path/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "got path\n") }) mux.HandleFunc("/task/{id}/", func(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") fmt.Fprintf(w, "handling task with id=%v\n", id) }) http.ListenAndServe("localhost:8090", mux) }
Erfahrene Go-Programmierer können sofort zwei neue Funktionen erkennen:
- Im ersten Handler wird die HTTP-Methode (in diesem Beispiel GET) explizit als Teil des Musters verwendet. Dies bedeutet, dass dieser Handler nur auf GET-Anfragen für Pfade antwortet, die mit /path/ beginnen, und keine Anfragen anderer HTTP-Methoden verarbeitet.
- Im zweiten Handler enthält die zweite Pfadkomponente - {id} einen Platzhalter, der in früheren Versionen nicht unterstützt wurde. Dieser Platzhalter kann mit einer einzelnen Pfadkomponente übereinstimmen, und der Handler kann den übereinstimmenden Wert über die PathValue-Methode der Anfrage abrufen.
Das Folgende ist ein Beispiel zum Testen dieses Servers mit dem curl-Befehl:
$ gotip run sample.go # Test in another terminal $ curl localhost:8090/what/ 404 page not found $ curl localhost:8090/path/ got path $ curl -X POST localhost:8090/path/ Method Not Allowed $ curl localhost:8090/task/leapcell/ handling task with id=leapcell
Aus den Testergebnissen ist ersichtlich, dass der Server POST-Anfragen an /path/ ablehnt und nur GET-Anfragen zulässt (curl verwendet standardmässig GET-Anfragen). Gleichzeitig wird dem ID-Platzhalter der entsprechende Wert zugewiesen, wenn die Anfrage übereinstimmt. Es wird empfohlen, dass Entwickler die Dokumentation des neuen ServeMux im Detail lesen, um weitere Funktionen zu verstehen, z. B. Regeln für nachgestellte Pfade und Platzhaltermatching mit {id} sowie das strikte Matching von Pfaden, die mit {$} enden.
(II) Behandlung von Musterkonflikten
Der Vorschlag widmet den möglichen Konfliktproblemen zwischen verschiedenen Mustern besondere Aufmerksamkeit. Das Folgende ist ein Beispiel:
mux := http.NewServeMux() mux.HandleFunc("/task/{id}/status/", func(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") fmt.Fprintf(w, "handling task status with id=%v\n", id) }) mux.HandleFunc("/task/0/{action}/", func(w http.ResponseWriter, r *http.Request) { action := r.PathValue("action") fmt.Fprintf(w, "handling task 0 with action=%v\n", action) })
Wenn der Server eine Anfrage für /task/0/status/ empfängt, können beide Handler mit dieser Anfrage übereinstimmen. Die neue ServeMux-Dokumentation beschreibt detailliert die Musterprioritätsregeln und die Behandlung potenzieller Konflikte. Wenn ein Konflikt auftritt, löst der Registrierungsprozess eine Panik aus. Für das obige Beispiel wird die folgende Fehlermeldung angezeigt:
panic: pattern "/task/0/{action}/" (registered at sample - conflict.go:14) conflicts with pattern "/task/{id}/status/" (registered at sample - conflict.go:10):
/task/0/{action}/ and /task/{id}/status/ both match some paths, like "/task/0/status/".
But neither is more specific than the other.
/task/0/{action}/ matches "/task/0/action/", but /task/{id}/status/ doesn't.
/task/{id}/status/ matches "/task/id/status/", but /task/0/{action}/ doesn't.
Diese Fehlermeldung ist detailliert und praktisch. In komplexen Registrierungsszenarien (insbesondere wenn Muster an mehreren Stellen im Quellcode registriert sind) können diese Details Entwicklern helfen, Konfliktprobleme schnell zu lokalisieren und zu beheben.
III. Implementieren eines Servers mit dem neuen Mux
Die REST-Server in der Go-Serie implementierten einen einfachen Server für eine Task-/To-do-Listenanwendung in Go unter Verwendung mehrerer Methoden. Der erste Teil wurde basierend auf der Standardbibliothek implementiert, und der zweite Teil implementierte denselben Server mithilfe des Gorilla/Mux-Routers neu. Jetzt ist es von grosser Bedeutung, diesen Server mit dem erweiterten Mux von Go 1.22 erneut zu implementieren, und es ist auch interessant, ihn mit der Lösung mit Gorilla/Mux zu vergleichen.
(I) Beispiel für die Musterregistrierung
Das Folgende ist ein repräsentativer Musterregistrierungscode:
mux := http.NewServeMux() server := NewTaskServer() mux.HandleFunc("POST /task/", server.createTaskHandler) mux.HandleFunc("GET /task/", server.getAllTasksHandler) mux.HandleFunc("DELETE /task/", server.deleteAllTasksHandler) mux.HandleFunc("GET /task/{id}/", server.getTaskHandler) mux.HandleFunc("DELETE /task/{id}/", server.deleteTaskHandler) mux.HandleFunc("GET /tag/{tag}/", server.tagHandler) mux.HandleFunc("GET /due/{year}/{month}/{day}/", server.dueHandler)
Ähnlich wie im Gorilla/Mux-Beispiel werden hier Anfragen mit demselben Pfad mithilfe bestimmter HTTP-Methoden an verschiedene Handler weitergeleitet. Bei Verwendung des alten http.ServeMux würden solche Matcher Anfragen an denselben Handler leiten, und der Handler würde dann nachfolgende Operationen basierend auf der Anfragemethode entscheiden.
(II) Handler-Beispiel
Das Folgende ist ein Codebeispiel eines Handlers:
func (ts *taskServer) getTaskHandler(w http.ResponseWriter, req *http.Request) { log.Printf("handling get task at %s\n", req.URL.Path) id, err := strconv.Atoi(req.PathValue("id")) if err!= nil { http.Error(w, "invalid id", http.StatusBadRequest) return } task, err := ts.store.GetTask(id) if err!= nil { http.Error(w, err.Error(), http.StatusNotFound) return } renderJSON(w, task) }
Dieser Handler extrahiert den ID-Wert aus req.PathValue("id"), was der Gorilla-Methode ähnelt. Da der reguläre Ausdruck jedoch nicht verwendet wird, um anzugeben, dass {id} nur mit ganzen Zahlen übereinstimmt, muss auf den von strconv.Atoi zurückgegebenen Fehler geachtet werden.
Insgesamt ist das Endergebnis der Lösung mit Gorilla/Mux recht ähnlich. Verglichen mit der traditionellen Standardbibliotheksmethode kann der neue Mux komplexere Routing-Operationen ausführen, wodurch die Notwendigkeit verringert wird, Routing-Entscheidungen dem Handler selbst zu überlassen, und die Entwicklungseffizienz und Wartbarkeit des Codes verbessert werden.
IV. Fazit
"Welche Router-Bibliothek soll ich wählen?" war schon immer eine häufige Frage für Go-Anfänger. Nach der Veröffentlichung von Go 1.22 kann sich die Antwort auf diese Frage ändern. Viele Entwickler werden feststellen, dass der neue Standardbibliotheks-Mux ausreicht, um ihre Anforderungen zu erfüllen, wodurch die Notwendigkeit entfällt, sich auf Pakete von Drittanbietern zu verlassen.
Natürlich werden einige Entwickler weiterhin die vertrauten Bibliotheken von Drittanbietern wählen, was auch vernünftig ist. Router wie Gorilla/Mux haben immer noch mehr Funktionen als die Standardbibliothek. Darüber hinaus werden viele Go-Programmierer schlanke Frameworks wie Gin wählen, da diese nicht nur einen Router, sondern auch zusätzliche Tools zur Erstellung eines Web-Backends bieten.
Zusammenfassend lässt sich sagen, dass die Optimierung der Standardbibliothek http.ServeMux in Go 1.22 zweifellos eine positive Veränderung ist. Unabhängig davon, ob Entwickler sich für die Verwendung von Drittanbieterpaketen entscheiden oder sich an die Standardbibliothek halten, ist die Erweiterung der Funktionalität der Standardbibliothek für die gesamte Go-Entwicklungsgemeinschaft von Vorteil.
Leapcell: Die beste serverlose Plattform für Go-App-Hosting, asynchrone Aufgaben und Redis
Schliesslich empfehlen wir eine Plattform, die am besten für die Bereitstellung von Go-Diensten geeignet ist: Leapcell
1. Unterstützung mehrerer Sprachen
- Entwickeln Sie mit JavaScript, Python, Go oder Rust.
2. Stellen Sie unbegrenzt viele Projekte kostenlos bereit
- Zahlen Sie nur für die Nutzung - keine Anfragen, keine Gebühren.
3. Unschlagbare Kosteneffizienz
- Pay - as - you - go ohne Leerlaufgebühren.
- Beispiel: 25 US-Dollar unterstützen 6,94 Millionen Anfragen bei einer durchschnittlichen Antwortzeit von 60 ms.
4. Optimiertes Entwicklererlebnis
- Intuitive Benutzeroberfläche für mühelose Einrichtung.
- Vollautomatische CI/CD-Pipelines und GitOps-Integration.
- Echtzeitmetriken und Protokollierung für umsetzbare Erkenntnisse.
5. Mühelose Skalierbarkeit und hohe Leistung
- Automatische Skalierung zur einfachen Handhabung hoher Parallelität.
- Null Betriebsaufwand - konzentrieren Sie sich einfach auf das Erstellen.
Erfahren Sie mehr in der Dokumentation!
Leapcell Twitter: https://x.com/LeapcellHQ