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:
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"
)
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
Em seguida, execute seu servidor:
go run server.go
Agora você tem um servidor web Go net/http rodando em localhost:3000
.
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 não é a framework. É uma biblioteca que é desenhada para trabalhar diretamente com net/http.
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()
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.
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)
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
)
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"
)
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"
)
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())
}
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),
))
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"
)
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.
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"
)
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"
)
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
}
Este middleware loga cada entrada de requisição e resposta.
Exemplo:
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)
}
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
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 |
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
gin e fresh são aplicativos para autoreload do Negroni.
- Usando um contexto para passar informação de um middleware para o manipulador final
- Entendendo middleware
Negroni é obsessivamente desenhado por ninguém menos que Code Gangsta