Negroni

May 3, 2025 · View on GitHub

GoDoc Build Status codebeat codecov

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:

MiddlewareAutorDescrição
authzYang LuoACL, RBAC, ABAC Authorization middlware based on Casbin
bindingMatt HoltData binding from HTTP requests into structs
cloudwatchColin SteeleAWS cloudwatch metrics middleware
corsOlivier PoitreyCross Origin Resource Sharing (CORS) support
cspAwake NetworksContent Security Policy (CSP) support
delayJeff MartinezAdd delays/latency to endpoints. Useful when testing effects of high latency
New Relic Go AgentYadvendar ChampawatOfficial New Relic Go Agent (currently in beta)
gorelicJingwen Owen OuNew Relic agent for Go runtime
GracefulTyler BunnellGraceful HTTP Shutdown
gzipphyberGZIP response compression
JWT MiddlewareAuth0Middleware checks for a JWT on the Authorization header on incoming requests and decodes it
logrusDan BuchLogrus-based logger
oauth2David BochenskioAuth2 middleware
ontheflyAlexander RødsethGenerate TinySVG, HTML and CSS on the fly
permissions2Alexander RødsethCookies, users and permissions
prometheusRene ZbindenEasily create metrics endpoint for the prometheus instrumentation tool
renderCory JacobsenRender JSON, XML and HTML templates
RestGatePrasanga SiripalaSecure authentication for REST API endpoints
secureCory JacobsenMiddleware that implements a few quick security wins
sessionsDavid BochenskiSession Management
statsFlorent MessaStore information about your web application (response time, etc.)
VanGoHTaylor WrobelConfigurable AWS-Style HMAC authentication middleware
xrequestidAndrea FranzMiddleware that assigns a random X-Request-Id header to each request
mgo sessionJoel JamesMiddleware that handles creating and closing mgo sessions per request
digitsBilal AmarniMiddleware that handles Twitter Digits authentication
statsChirag GuptaMiddleware 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

Sobre

Negroni é obsessivamente desenhado por ninguém menos que Code Gangsta