Skip to content

Latest commit

 

History

History
512 lines (384 loc) · 18.5 KB

README_fr_FR.md

File metadata and controls

512 lines (384 loc) · 18.5 KB

Negroni

GoDoc Build Status codebeat codecov

Note: Ce projet était initiallement connu comme github.com/codegangsta/negroni -- Github redirigera automatiquement les requêtes vers ce dépôt. Nous vous recommandons néanmoins d'utiliser la référence vers ce nouveau dépôt pour plus de clarté.

Negroni approche la question de la création de middleware de manière pragmatique. La librairie se veut légère, non intrusive et encourage l'utilisation des Handlers de la librairie standard net/http.

Si vous appréciez le projet Martini et estimez qu'une certaine magie s'en dégage, Negroni sera sans doute plus approprié.

Démarrer avec Negroni

Une fois Go installé et votre variable GOPATH à jour, créez votre premier fichier .go et nommez le server.go.

package main

import (
  "fmt"
  "net/http"

  "github.com/urfave/negroni"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(w, "Welcome to the home page!")
  })

  n := negroni.Classic() // Inclue les "middlewares" par défaut.
  n.UseHandler(mux)

  http.ListenAndServe(":3000", n)
}

Installez au préalable le paquet Negroni (NOTE: Une version de Go >= go 1.1 est nécessaire):

go get github.com/urfave/negroni

Démarrez le serveur:

go run server.go

Vous avez dès à présent un serveur web Go basé sur net/http disponible à l'adresse localhost:3000.

Paquets

Si vous utilisez Debian, negroni est aussi disponible en tant que [paquet] (https://packages.debian.org/sid/golang-github-urfave-negroni-dev). La commande apt install golang-github-urfave-negroni-dev vous permettra de l'installer (À ce jour, vous les trouverez dans les dépôts sid).

Negroni est-il un framework ?

Negroni n'est pas un framework. Considérez le comme une librairie centrée sur l'utilisation de middleware développés pour fonctionner directement avec la librairie net/http.

Redirection (Routing) ?

Negroni est BYOR (Bring your own Router, Apporter votre propre routeur). La communauté Go offre un nombre important de routeurs et Negroni met tout en oeuvre pour fonctionner avec chacun d'entre eux en assurant un support complet de la librairie net/http. Par exemple, une utilisation avec Gorilla Mux se présente sous la forme:

router := mux.NewRouter()
router.HandleFunc("/", HomeHandler)

n := negroni.New(Middleware1, Middleware2)
// on peut utiliser également la fonction Use() pour ajouter un "middleware"
n.Use(Middleware3)
// le routeur se trouve toujours en dernier.
n.UseHandler(router)

http.ListenAndServe(":3001", n)

negroni.Classic()

L'instance negroni.Classic() propose par défaut trois middlewares qui seront utiles à la plupart des applications:

Elle offre un démarrage aisé sans recourir à la configuration pour utiliser quelques-unes des fonctions les plus utiles de Negroni.

Handlers

Negroni offre un flux bidirectionnel via les middlewares (aller-retour entre la requête et la réponse). Tout repose sur l'interface negroni.Handler :

type Handler interface {
 ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
}

Si un middleware n'a pas écrit au ResponseWriter, il doit faire appel au prochain http.Handlerfunc de la chaîne pour que le prochain middleware soit appelé:

func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
  // faire quelque chose avant
  next(rw, r)
  // faire quelque chose après
}

Vous pouvez insérer votre middleware dans la chaîne en utilisant la fonction Use:

n := negroni.New()
n.Use(negroni.HandlerFunc(MyMiddleware))

Vous pour également utiliser un http.Handler classique:

n := negroni.New()

mux := http.NewServeMux()
// définissez vos routes

n.UseHandler(mux)

http.ListenAndServe(":3000", n)

With()

La méthode With() vous permet de regrouper un ou plusieurs Handler au sein d'une nouvelle instance Negroni. Cette dernière est la combinaison des Handlers de l'ancienne et de la nouvelle instance.

// "middleware" à réutiliser.
common := negroni.New()
common.Use(MyMiddleware1)
common.Use(MyMiddleware2)

// `specific` devient une nouvelle instance avec les "handlers" provenant de `common` ainsi
// que ceux passés en paramètres.
specific := common.With(
	SpecificMiddleware1,
	SpecificMiddleware2
)

Run()

Negroni peut-être démarré en utilisant la méthode Run(). Cette dernière prend en paramètre l'adresse du serveur, à l'instar de la méthode http.ListenAndServe.

package main

import (
  "github.com/urfave/negroni"
)

func main() {
  n := negroni.Classic()
  n.Run(":8080")
}

Si aucune adresse n'est renseignée, la variable d'environnement PORT est utilisée. Si cette dernière n'est pas définie, l'adresse par défaut est utilisée. Pour une description détaillée, veuillez-vous référer à la documentation de la méthode [Run]((https://godoc.org/github.com/urfave/negroni#Negroni.Run).

De manière générale, vous voudrez vous servir de la librairie net/http et utiliser negroni comme un simple Handler pour plus de flexibilité.

Par exemple:

package main

import (
  "fmt"
  "log"
  "net/http"
  "time"

  "github.com/urfave/negroni"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(w, "Welcome to the home page!")
  })

  n := negroni.Classic() // Inclue les "middlewares" par défaut
  n.UseHandler(mux)

  s := &http.Server{
    Addr:           ":8080",
    Handler:        n,
    ReadTimeout:    10 * time.Second,
    WriteTimeout:   10 * time.Second,
    MaxHeaderBytes: 1 << 20,
  }
  log.Fatal(s.ListenAndServe())
}

Redirection spécifique

Si un ensemble de routes nécessite l'appel à des middleware spécifiques, vous pouvez simplement créer une nouvelle instance Negroni et l'utiliser comme Handler pour cet ensemble.

router := mux.NewRouter()
adminRoutes := mux.NewRouter()
// ajout des routes relatives à l'administration

// Création d'une nouvelle instance pour le "middleware" admin.
router.PathPrefix("/admin").Handler(negroni.New(
  Middleware1,
  Middleware2,
  negroni.Wrap(adminRoutes),
))

Si vous utilisez Gorilla Mux, vous pourriez utiliser un subrouter:

router := mux.NewRouter()
subRouter := mux.NewRouter().PathPrefix("/subpath").Subrouter().StrictSlash(true)
subRouter.HandleFunc("/", someSubpathHandler) // "/subpath/"
subRouter.HandleFunc("/:id", someSubpathHandler) // "/subpath/:id"

// "/subpath" est nécessaire pour assurer la cohésion entre le `subrouter` et le routeur principal
router.PathPrefix("/subpath").Handler(negroni.New(
  Middleware1,
  Middleware2,
  negroni.Wrap(subRouter),
))

La méthode With() peut aider à réduire la duplication des middlewares partagés par plusieurs routes.

router := mux.NewRouter()
apiRoutes := mux.NewRouter()
// ajout des routes api ici
webRoutes := mux.NewRouter()
// ajout des routes web ici

// création d'un "middleware" commun pour faciliter le partage
common := negroni.New(
	Middleware1,
	Middleware2,
)

// création d'une nouvelle instance pour le "middleware"
// api en utilisant le "middleware" commun comme base.
router.PathPrefix("/api").Handler(common.With(
  APIMiddleware1,
  negroni.Wrap(apiRoutes),
))
// création d'une nouvelle instance pour le "middleware"
// web en utilisant le "middleware" commun comme base.
router.PathPrefix("/web").Handler(common.With(
  WebMiddleware1,
  negroni.Wrap(webRoutes),
))

Middlewares fournis

Static

Ce middleware va servir les fichiers présents sur le système de fichiers. Si un fichier n'existe pas, il transmet la requête au middleware suivant. Si vous souhaitez retourner le message 404 File Not Found pour les fichiers non existants, vous pouvez utiliser la fonction http.FileServer comme Handler.

Exemple:

package main

import (
  "fmt"
  "net/http"

  "github.com/urfave/negroni"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(w, "Welcome to the home page!")
  })

  // Exemple d'usage de la fonction http.FileServer pour avoir un comportement similaire à un
  // serveur HTTP "standard" plutôt que le comportement "middleware"
  // mux.Handle("/public", http.FileServer(http.Dir("/home/public")))

  n := negroni.New()
  n.Use(negroni.NewStatic(http.Dir("/tmp")))
  n.UseHandler(mux)

  http.ListenAndServe(":3002", n)
}

Ce programme servira les fichiers depuis le répertoire /tmp en premier lieu. Si le fichier n'est pas trouvé, il transmet la requête au middleware suivant.

Recupération (Recovery)

Ce middleware capture les appels à panic et renvoie une réponse 500 à la requête correspondante. Si un autre middleware a déjà renvoyé une réponse (vide ou non), le renvoie de la réponse 500 au client échouera, le client en ayant déjà obtenu une.

Il est possible d'adjoindre au middleware une fonction de type PanicHandlerFunc pour collecter les erreurs 500 et les transmettre à un service de rapport d'erreur tels Sentry ou Airbrake.

Exemple:

package main

import (
  "net/http"

  "github.com/urfave/negroni"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    panic("oh no")
  })

  n := negroni.New()
  n.Use(negroni.NewRecovery())
  n.UseHandler(mux)

  http.ListenAndServe(":3003", n)
}

Ce programme renverra une erreur 500 Internal Server Error à chaque requête reçue. Il transmettra à son logger associé la trace de la pile d'exécution et affichera cette même trace sur la sortie standard si la valeur PrintStack est mise à true. (valeur par défaut)

Exemple avec l'utilisation d'une PanicHandlerFunc:

package main

import (
  "net/http"

  "github.com/urfave/negroni"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    panic("oh no")
  })

  n := negroni.New()
  recovery := negroni.NewRecovery()
  recovery.PanicHandlerFunc = reportToSentry
  n.Use(recovery)
  n.UseHandler(mux)

  http.ListenAndServe(":3003", n)
}

func reportToSentry(info *negroni.PanicInformation) {
    // code envoyant le rapport d'erreur à Sentry
}

Journalisation (Logger)

Ce middleware va logger toutes les requêtes et réponses.

Exemple:

package main

import (
  "fmt"
  "net/http"

  "github.com/urfave/negroni"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(w, "Welcome to the home page!")
  })

  n := negroni.New()
  n.Use(negroni.NewLogger())
  n.UseHandler(mux)

  http.ListenAndServe(":3004", n)
}

Ce programme affichera un log similaire à celui-ci pour chaque requête/réponse:

[negroni] 2017-10-04T14:56:25+02:00 | 200 |      378µs | localhost:3004 | GET /

Il est possible de modifier le format par défaut en utilisant la fonction SetFormat. Le format est template dont les champs associés sont les propriétés de l'objet LoggerEntry.

Par exemple:

l.SetFormat("[{{.Status}} {{.Duration}}] - {{.Request.UserAgent}}")

Ce format proposera un affichage similaire à: [200 18.263µs] - Go-User-Agent/1.1

Middlewares tiers

Vous trouverez ici une liste de middlewares compatibles avec Negroni. N'hésitez pas à créer une PR pour renseigner un middleware de votre cru:

Middleware Author Description
authz Yang Luo Un middleware de gestion d'accès ACL, RBAC, ABAC basé sur Casbin
binding Matt Holt Associez facilement les données des requêtes HTTP vers des structures Go
cloudwatch Colin Steele Middleware pour utiliser les métriques AWS cloudwatch
cors Olivier Poitrey Support Cross Origin Resource Sharing (CORS)
csp Awake Networks Support Content Security Policy (CSP)
delay Jeff Martinez Ajouter des délais de réponse sur les routes. Utile pour tester les effets de la latence.
New Relic Go Agent Yadvendar Champawat Agent New Relic Go officiel
gorelic Jingwen Owen Ou Agent New Relic agent pour le runtime Go
Graceful Tyler Bunnell Graceful HTTP Shutdown
gzip phyber Compression GZIP des réponses
JWT Middleware Auth0 Middleware qui vérifie la présence d'un JWT dans le header Authorization et le décode
JWT Middleware Marcelo Fuentes JWT middleware pour golang
logrus Dan Buch Logger basé sur Logrus
oauth2 David Bochenski Middleware oAuth2
onthefly Alexander Rødseth Générer des éléments TinySVG, HTML et CSS à la volée
permissions2 Alexander Rødseth Cookies, utilisateurs et permissions
prometheus Rene Zbinden Créer des métriques facilement avec l'outil prometheus
prometheus Xabier Larrakoetxea Prometheus Créer des métriques, avec de nombreuses options, qui suivent les standards et sont mesurées de manière efficace
render Cory Jacobsen Rendre des templates JSON, XML et HTML
RestGate Prasanga Siripala Authentification sécurisée pour les APIs REST
secure Cory Jacobsen Middleware implémentant des basiques de sécurité
sessions David Bochenski Gestions des sessions
stats Florent Messa Stockez des informations à propos de votre application web (temps de réponse, etc.)
VanGoH Taylor Wrobel Middleware d'authentification HMAC configurable basée sur AWS-Style
xrequestid Andrea Franz Un middleware qui assigne un header X-Request-Id à chaque requête
mgo session Joel James Un middleware qui gère les sessions mgo pour chaque requête (ouverture, fermeture)
digits Bilal Amarni Un middleware qui gère l'authentification via Twitter Digits
stats Chirag Gupta Middleware qui gère les statistiques qps et la latence pour vos points de terminaison et les envoie de manière asynchrone à influx db
Chaos Marc Falzon Middleware pour injecter programmatiquement du comportement chaotique dans une application

Exemples

Alexander Rødseth a créé mooseware, un squelette pour écrire un middleware Negroni.

Prasanga Siripala a créé un squelette pour les applications web basées sur Go et Negroni: Go-Skeleton

Rechargement automatique du code ?

gin et fresh permettent tous deux de recharger les applications Negroni suite à une modification opérée dans le code.

Lectures pour les débutants avec Go et Negroni

À propos

Negroni est obsessivement développé par nulle autre personne que Code Gangsta