Negroni
May 3, 2025 · View on GitHub
Notice: Esta é uma biblioteca conhecida anteriormente como
github.com/codegangsta/negroni -- Github irá redirecionar automaticamente as requisições
para este repositório, mas recomendamos atualizar suas referências por clareza.
O Negroni é uma abordagem idiomática para middlewares web em Go. É pequeno, não intrusivo, e incentiva o uso da biblioteca net/http.
Se gosta da idéia do Martini, mas acha que contém muita mágica, então Negroni é ideal.
Idiomas traduzidos:
Começando
Depois de instalar a linguagem Go e definir seu GOPATH, crie seu primeiro arquivo .go.
Chamaremos ele de server.go.
package main
import (
"fmt"
"net/http"
"github.com/urfave/negroni/v3"
)
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() // Includes some default middlewares
n.UseHandler(mux)
http.ListenAndServe(":3000", n)
}
Depois instale o pacote Negroni (go 1.1 ou superior)
go get github.com/urfave/negroni/v3
Em seguida, execute seu servidor:
go run server.go
Agora você tem um servidor web Go net/http rodando em localhost:3000.
Empacotamento
Se você está no Debian, negroni também está disponível como um pacote que
você pode instalar via apt install golang-github-urfave-negroni-dev (no momento que isto foi escrito, ele estava em repositórios do sid).
Negroni é um Framework?
Negroni não é a framework. É uma biblioteca que é desenhada para trabalhar diretamente com net/http.
Roteamento?
Negroni é TSPR(Traga seu próprio Roteamento). A comunidade Go já tem um grande número de roteadores http disponíveis, Negroni tenta rodar bem com todos eles pelo suporte total net/http/ Por exemplo, a integração com Gorilla Mux se parece com isso:
router := mux.NewRouter()
router.HandleFunc("/", HomeHandler)
n := negroni.New(Middleware1, Middleware2)
// Or use a middleware with the Use() function
n.Use(Middleware3)
// router goes last
n.UseHandler(router)
n.Run(":3000")
negroni.Classic()
negroni.Classic() fornece alguns middlewares padrão que são úteis para maioria das aplicações:
negroni.Recovery- Panic Recovery Middleware.negroni.Logging- Request/Response Logging Middleware.negroni.Static- Static File serving under the "public" directory.
Isso torna muito fácil começar com alguns recursos úteis do Negroni.
Handlers
Negroni fornece um middleware de fluxo bidirecional. Isso é feito através da interface negroni.Handler:
type Handler interface {
ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
}
Se um middleware não tenha escrito o ResponseWriter, ele deve chamar a próxima http.HandlerFunc na cadeia para produzir o próximo handler middleware. Isso pode ser usado muito bem:
func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
// do some stuff before
next(rw, r)
// do some stuff after
}
E pode mapear isso para a cadeia de handler com a função Use:
n := negroni.New()
n.Use(negroni.HandlerFunc(MyMiddleware))
Você também pode mapear http.Handler antigos:
n := negroni.New()
mux := http.NewServeMux()
// map your routes
n.UseHandler(mux)
http.ListenAndServe(":3000", n)
With()
Negroni tem uma conveniente função chamada With. With pega uma ou mais
instâncias Handler e retorna um novo Negroni com a combinação dos handlers de receivers e os novos handlers.
// middleware we want to reuse
common := negroni.New()
common.Use(MyMiddleware1)
common.Use(MyMiddleware2)
// `specific` is a new negroni with the handlers from `common` combined with the
// the handlers passed in
specific := common.With(
SpecificMiddleware1,
SpecificMiddleware2
)
Run()
Negroni tem uma função de conveniência chamada Run. Run pega um endereço de string idêntico para http.ListenAndServe.
package main
import (
"github.com/urfave/negroni/v3"
)
func main() {
n := negroni.Classic()
n.Run(":8080")
}
Se nenhum endereço for fornecido, a variável de ambiente PORT é usada no lugar.
Se a variável de ambiente PORT não for definida, o endereço padrão será usado.
Veja Run para uma descrição completa.
No geral, você irá quere usar métodos net/http e passar negroni como um Handler,
como ele é mais flexível, e.g.:
package main
import (
"fmt"
"log"
"net/http"
"time"
"github.com/urfave/negroni/v3"
)
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() // Includes some default middlewares
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())
}
Middleware para Rotas Específicas
Se você tem um grupo de rota com rotas que precisam ser executadas por um middleware específico, pode simplesmente criar uma nova instância de Negroni e usar no seu Manipulador de rota.
router := mux.NewRouter()
adminRoutes := mux.NewRouter()
// add admin routes here
// Create a new negroni for the admin middleware
router.PathPrefix("/admin").Handler(negroni.New(
Middleware1,
Middleware2,
negroni.Wrap(adminRoutes),
))
Se você está usando Gorilla Mux, aqui é um exemplo usando uma subrota:
router := mux.NewRouter()
subRouter := mux.NewRouter().PathPrefix("/subpath").Subrouter().StrictSlash(true)
subRouter.HandleFunc("/", someSubpathHandler) // "/subpath/"
subRouter.HandleFunc("/:id", someSubpathHandler) // "/subpath/:id"
// "/subpath" is necessary to ensure the subRouter and main router linkup
router.PathPrefix("/subpath").Handler(negroni.New(
Middleware1,
Middleware2,
negroni.Wrap(subRouter),
))
With() pode ser usado para eliminar redundância por middlewares compartilhados através de rotas.
router := mux.NewRouter()
apiRoutes := mux.NewRouter()
// add api routes here
webRoutes := mux.NewRouter()
// add web routes here
// create common middleware to be shared across routes
common := negroni.New(
Middleware1,
Middleware2,
)
// create a new negroni for the api middleware
// using the common middleware as a base
router.PathPrefix("/api").Handler(common.With(
APIMiddleware1,
negroni.Wrap(apiRoutes),
))
// create a new negroni for the web middleware
// using the common middleware as a base
router.PathPrefix("/web").Handler(common.With(
WebMiddleware1,
negroni.Wrap(webRoutes),
))
Bundled Middleware
Static
Este middleware servirá arquivos do filesystem. Se os arquivos não existerem,
ele substituirá a requisição para o próximo middleware. Se você quer que as
requisições para arquivos não existentes retorne um 404 File Not Found para o user
você deve olhar em usando
http.FileServer como um handler.
Exemplo:
package main
import (
"fmt"
"net/http"
"github.com/urfave/negroni/v3"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "Welcome to the home page!")
})
// Example of using a http.FileServer if you want "server-like" rather than "middleware" behavior
// 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)
}
Serviá arquivos do diretório /tmp primeiro, mas substituirá chamadas para o
próximo handler se a requisição não encontrar um arquivo no filesystem.
Recovery
Este middleware pega repostas de panic com um código de resposta 500. Se
algum outro middleware escreveu um código resposta ou conteúdo, este middleware
falhará corretamente enviando um 500 para o cliente, como o cliente já recebeu
o código de resposta HTTP. Adicionalmente um PanicHandlerFunc pode ser anexado
para reportar 500 para um serviço de report como um Sentry ou Airbrake.
Exemplo:
package main
import (
"net/http"
"github.com/urfave/negroni/v3"
)
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)
}
Irá retornar um 500 Internal Server Error para cada requisição. Ele também irá
registrar stack trace bem como um print na stack tarce para quem fez a requisição
if PrintStack estiver setado como true (o padrão).
Exemplo com handler de erro:
package main
import (
"net/http"
"github.com/urfave/negroni/v3"
)
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) {
// write code here to report error to Sentry
}
Logger
Este middleware loga cada entrada de requisição e resposta.
Exemplo:
package main
import (
"fmt"
"net/http"
"github.com/urfave/negroni/v3"
)
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)
}
Irá printar um log simular para:
[negroni] 2017-10-04T14:56:25+02:00 | 200 | 378µs | localhost:3004 | GET /
em cada request.
Você também pode definir seu próprio formato de log chamando a função SetFormat.
O formato é uma string de template como os campos como mencionados na struct LoggerEntry.
Então, como exemplo -
l.SetFormat("[{{.Status}} {{.Duration}}] - {{.Request.UserAgent}}")
Mostrará algo como - [200 18.263µs] - Go-User-Agent/1.1
Middleware de Terceiros
Aqui está uma lista atual de Middleware Compatíveis com Negroni. Sinta se livre para mandar um PR vinculando seu middleware se construiu um:
| Middleware | Autor | Descrição |
|---|---|---|
| authz | Yang Luo | ACL, RBAC, ABAC Authorization middlware based on Casbin |
| binding | Matt Holt | Data binding from HTTP requests into structs |
| cloudwatch | Colin Steele | AWS cloudwatch metrics middleware |
| cors | Olivier Poitrey | Cross Origin Resource Sharing (CORS) support |
| csp | Awake Networks | Content Security Policy (CSP) support |
| delay | Jeff Martinez | Add delays/latency to endpoints. Useful when testing effects of high latency |
| New Relic Go Agent | Yadvendar Champawat | Official New Relic Go Agent (currently in beta) |
| gorelic | Jingwen Owen Ou | New Relic agent for Go runtime |
| Graceful | Tyler Bunnell | Graceful HTTP Shutdown |
| gzip | phyber | GZIP response compression |
| JWT Middleware | Auth0 | Middleware checks for a JWT on the Authorization header on incoming requests and decodes it |
| logrus | Dan Buch | Logrus-based logger |
| oauth2 | David Bochenski | oAuth2 middleware |
| onthefly | Alexander Rødseth | Generate TinySVG, HTML and CSS on the fly |
| permissions2 | Alexander Rødseth | Cookies, users and permissions |
| prometheus | Rene Zbinden | Easily create metrics endpoint for the prometheus instrumentation tool |
| render | Cory Jacobsen | Render JSON, XML and HTML templates |
| RestGate | Prasanga Siripala | Secure authentication for REST API endpoints |
| secure | Cory Jacobsen | Middleware that implements a few quick security wins |
| sessions | David Bochenski | Session Management |
| stats | Florent Messa | Store information about your web application (response time, etc.) |
| VanGoH | Taylor Wrobel | Configurable AWS-Style HMAC authentication middleware |
| xrequestid | Andrea Franz | Middleware that assigns a random X-Request-Id header to each request |
| mgo session | Joel James | Middleware that handles creating and closing mgo sessions per request |
| digits | Bilal Amarni | Middleware that handles Twitter Digits authentication |
| stats | Chirag Gupta | Middleware that manages qps and latency stats for your endpoints and asynchronously flushes them to influx db |
Exemplos
Alexander Rødseth criou mooseware, uma estrutura para escrever um handler middleware Negroni.
Prasanga Siripala Criou um efetivo estrutura esqueleto para projetos Go/Negroni baseados na web: Go-Skeleton
Servidor com autoreload?
gin e fresh são aplicativos para autoreload do Negroni.
Leitura Essencial para Iniciantes em Go & Negroni
- Usando um contexto para passar informação de um middleware para o manipulador final
- Entendendo middleware
Sobre
Negroni é obsessivamente desenhado por ninguém menos que Code Gangsta