
Il y a cinq ans, j'ai commencé , ce qui m'a permis d'explorer Golang. J'ai réalisé que Go est un langage puissant, dont les possibilités sont complétées par de nombreuses bibliothÚques. Go est polyvalent : en particulier, il permet de développer sans problÚme des applications serveur.
Cet article est consacré à l'écriture d'un serveur en Go. Nous commencerons par des choses simples, comme « Bonjour monde ! », et nous finirons avec une application ayant les fonctionnalités suivantes :
â Utilisation de Letâs Encrypt pour HTTPS.
â Fonctionnement en tant que routeur API.
â Gestion de middleware.
â Traitement de fichiers statiques.
â ArrĂȘt propre.
Skillbox recommande : Cours pratique .
Rappelons-le : pour tous les lecteurs de « Habr » â une rĂ©duction de 10 000 roubles lors de l'inscription Ă tout cours Skillbox avec le code promo « Habr ».
Hello, world!
Créer un serveur web en Go peut se faire trÚs rapidement. Voici un exemple d'utilisation d'un gestionnaire qui renvoie le fameux « Hello, world ! » mentionné ci-dessus.
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World!")
})
http.ListenAndServe(":80", nil)
}AprÚs cela, si vous lancez l'application et ouvrez la page , vous verrez immédiatement le texte « Hello, world ! » (bien sûr, si tout fonctionne correctement).
Ensuite, nous utiliserons Ă plusieurs reprises le gestionnaire, mais d'abord, comprenons comment tout cela fonctionne.
net/http
L'exemple utilise le paquet , qui est l'outil principal en Go pour le développement aussi bien de serveurs que de clients HTTP. Pour comprendre le code, examinons le sens de trois éléments importants : http.Handler, http.ServeMux et http.Server.
Les gestionnaires HTTP
Lorsque nous recevons une requĂȘte, le gestionnaire l'analyse et forme une rĂ©ponse. Les gestionnaires en Go sont implĂ©mentĂ©s de la maniĂšre suivante :
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}Dans le premier exemple, nous utilisons la fonction d'assistance http.HandleFunc. Elle enveloppe une autre fonction qui, Ă son tour, prend http.ResponseWriter et http.Request dans ServeHTTP.
En d'autres termes, les gestionnaires en Golang sont reprĂ©sentĂ©s par une interface unique, ce qui offre de nombreuses possibilitĂ©s au programmeur. Par exemple, le middleware est implĂ©mentĂ© Ă l'aide d'un gestionnaire oĂč ServeHTTP fait d'abord quelque chose, puis appelle la mĂ©thode ServeHTTP d'un autre gestionnaire.
Comme mentionnĂ© prĂ©cĂ©demment, les gestionnaires ne font que former des rĂ©ponses aux requĂȘtes. Mais quel gestionnaire faut-il utiliser Ă un moment donnĂ© ?
Routage des requĂȘtes
Pour faire le bon choix, utilisez un multiplexeur HTTP. Dans plusieurs bibliothĂšques, il est appelĂ© muxer ou router, mais tout cela revient au mĂȘme. La fonction du multiplexeur consiste Ă analyser le chemin de la requĂȘte et Ă choisir le gestionnaire appropriĂ©.
Si vous avez besoin d'un support pour un routage complexe, il est préférable d'utiliser des bibliothÚques tierces. Parmi les plus avancées, on trouve et , ces bibliothÚques permettent d'implémenter un traitement intermédiaire sans trop de problÚmes. Grùce à elles, vous pouvez configurer le routage wildcard et accomplir plusieurs autres tùches. Leur avantage est la compatibilité avec les gestionnaires HTTP standards. En conséquence, vous pouvez écrire un code simple avec la possibilité de le modifier à l'avenir.
Travailler avec des frameworks complexes dans des situations normales nécessitera des solutions non standard, ce qui complique considérablement l'utilisation des gestionnaires par défaut. Pour créer la majorité des applications, une combinaison de la bibliothÚque par défaut et d'un routeur simple suffira.
Traitement des requĂȘtes
De plus, nous avons besoin d'un composant qui va « Ă©couter » les connexions entrantes et rediriger toutes les requĂȘtes vers le bon gestionnaire. Cette tĂąche est facilement gĂ©rĂ©e par http.Server.
Ci-dessous, il est montré que le serveur est responsable de toutes les tùches relatives au traitement des connexions. Cela inclut, par exemple, le fonctionnement avec le protocole TLS. Pour implémenter l'appel http.ListenAndServer, nous utilisons le serveur HTTP standard.
Examinons maintenant des exemples plus complexes.
Ajouter Letâs Encrypt
Par défaut, notre application fonctionne avec le protocole HTTP, mais il est recommandé d'utiliser le protocole HTTPS. En Go, cela peut se faire sans problÚme. Si vous avez obtenu un certificat et une clé privée, il suffit d'appeler ListenAndServeTLS en indiquant les bons fichiers de certificat et de clé.
http.ListenAndServeTLS(":443", "cert.pem", "key.pem", nil)On peut toujours faire mieux.
fournit des certificats gratuits avec la possibilité de mise à jour automatique. Pour utiliser le service, vous avez besoin du paquet autocert.
Le moyen le plus simple de le configurer est dâutiliser la mĂ©thode autocert.NewListener en combinaison avec http.Serve. La mĂ©thode permet dâobtenir et de mettre Ă jour des certificats TLS, tandis que le serveur HTTP traite les requĂȘtes :
http.Serve(autocert.NewListener("example.com"), nil)Si nous ouvrons dans le navigateur , nous obtiendrons la réponse HTTPS « Hello, world! ».
Si vous avez besoin d'une configuration plus minutieuse, il vaut mieux utiliser le gestionnaire autocert.Manager. Ensuite, nous créons notre propre instance http.Server (jusqu'à présent, nous l'avons utilisée par défaut) et ajoutons le gestionnaire dans la configuration TLS du serveur :
m := &autocert.Manager{
Cache: autocert.DirCache("golang-autocert"),
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist("example.org", "www.example.org"),
}
server := &http.Server{
Addr: ":443",
TLSConfig: m.TLSConfig(),
}
server.ListenAndServeTLS("", "")C'est une mĂ©thode simple pour mettre en Ćuvre un support complet de HTTPS avec renouvellement automatique du certificat.
Ajout de routes personnalisées
Le routeur par défaut inclus dans la bibliothÚque standard est bon, mais il est trÚs simple. La plupart des applications nécessitent une routage plus complexe, y compris des routes imbriquées et des routes wildcard ou une procédure d'établissement de motifs et de paramÚtres de chemins.
Dans ce cas, il vaut mieux utiliser les paquets et . Avec le dernier, nous apprendrons Ă travailler â ci-dessous un exemple.
DonnĂ© â le fichier api/v1/api.go, contenant les routes pour notre API :
/ HelloResponse is the JSON representation for a customized message
type HelloResponse struct {
Message string `json:"message"`
}
// HelloName returns a personalized JSON message
func HelloName(w http.ResponseWriter, r *http.Request) {
name := chi.URLParam(r, "name")
response := HelloResponse{
Message: fmt.Sprintf("Hello %s!", name),
}
jsonResponse(w, response, http.StatusOK)
}
// NewRouter returns an HTTP handler that implements the routes for the API
func NewRouter() http.Handler {
r := chi.NewRouter()
r.Get("/{name}", HelloName)
return r
}Nous définissons un préfixe api/vq pour les routes dans le fichier principal.
Nous pouvons alors le monter sur notre routeur principal sous le préfixe api/v1/ dans notre application principale :
// NewRouter returns a new HTTP handler that implements the main server routes
func NewRouter() http.Handler {
router := chi.NewRouter()
router.Mount("/api/v1/", v1.NewRouter())
return router
}
http.Serve(autocert.NewListener("example.com"), NewRouter())La simplicité de traitement des routes complexes en Go permet de simplifier la structuration pour le maintien de grandes applications complexes.
Travailler avec le middleware
Dans le cas du traitement intermédiaire, un gestionnaire HTTP est enveloppé dans un autre, ce qui permet d'effectuer rapidement l'authentification, la compression, la journalisation et quelques autres fonctions.
à titre d'exemple, considérons l'interface http.Handler, avec laquelle nous allons écrire un gestionnaire d'authentification des utilisateurs du service.
func RequireAuthentication(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !isAuthenticated(r) {
http.Redirect(w, r, "\/login", http.StatusTemporaryRedirect)
return
}
\/\/ En supposant que l'authentification réussie, exécutez le gestionnaire original
next.ServeHTTP(w, r)
})
}Il existe des routeurs tiers, comme chi, qui permettent d'élargir la fonctionnalité du traitement intermédiaire.
Travailler avec des fichiers statiques
La bibliothÚque standard de Go inclut des fonctionnalités pour le traitement de contenu statique, y compris des images, ainsi que des fichiers JavaScript et CSS. On peut y accéder via la fonction http.FileServer. Elle retourne un gestionnaire qui distribue des fichiers depuis un répertoire spécifique.
func NewRouter() http.Handler {
router := chi.NewRouter()
r.Get("/{name}", HelloName)
// Configuration for serving static files
staticPath, _ := filepath.Abs("../../static/")
fs := http.FileServer(http.Dir(staticPath))
router.Handle("/*", fs)
return rIl est important de se rappeler que http.Dir affiche le contenu du répertoire si le fichier index.html principal n'est pas présent. Dans ce cas, pour éviter toute compromission du répertoire, il convient d'utiliser le paquet .
ArrĂȘt correct
En Go, il existe Ă©galement une fonction permettant la fermeture correcte d'un serveur HTTP. Cela peut se faire Ă l'aide de la mĂ©thode Shutdown(). Le serveur fonctionne dans une goroutine, et ensuite, un canal Ă©coute pour recevoir un signal d'interruption. DĂšs que le signal est reçu, le serveur s'arrĂȘte, mais pas immĂ©diatement, aprĂšs quelques secondes.
handler := server.NewRouter()
srv := &http.Server{
Handler: handler,
}
go func() {
srv.Serve(autocert.NewListener(domains...))
}()
// Attendre un signal d'interruption
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
<-c
// Essayer un arrĂȘt gracieux
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
srv.Shutdown(ctx)En conclusion
Go est un langage puissant avec une bibliothĂšque standard presque universelle. Ses capacitĂ©s par dĂ©faut sont assez larges, et on peut les renforcer grĂące Ă des interfaces â ce qui permet de dĂ©velopper des serveurs HTTP vraiment fiables.
Skillbox recommande :
- Cours pratique de deux ans .
- Cours en ligne éducatif .
- Cours pratique d'un an .
Source : habr.com
