A collection of useful middleware for Go HTTP services & web applications 🛃



GoDoc CircleCI Sourcegraph

Package handlers is a collection of handlers (aka "HTTP middleware") for use with Go's net/http package (or any framework supporting http.Handler), including:

Other handlers are documented on the Gorilla website.


A simple example using handlers.LoggingHandler and handlers.CompressHandler:

import (

func main() {
    r := http.NewServeMux()

    // Only log requests to our admin dashboard to stdout
    r.Handle("/admin", handlers.LoggingHandler(os.Stdout, http.HandlerFunc(ShowAdminDashboard)))
    r.HandleFunc("/", ShowIndex)

    // Wrap our server with our gzip handler to gzip compress all responses.
    http.ListenAndServe(":8000", handlers.CompressHandler(r))


BSD licensed. See the included LICENSE file for details.

  • [bug] COmpressHandler is broken

    [bug] COmpressHandler is broken

    Everything was working till yesterday. it starts failing today. I am using the google cloud build , so it takes the latest mux from repo. Local mux which is old is working fine.

    I am using the compress handler like this

    http.ListenAndServe(":8080", handlers.CompressHandler(r))

    and serving static files.

    but all the browser are not able to read the content. I tested with Mozzila , chrome and Microsoft EDGE.

    Following error is shown


    When I use without compress , things works but now my server slow without compression


    opened by max202021 24
  • Using handler.CompressHandler with mux.NotFoundHandler

    Using handler.CompressHandler with mux.NotFoundHandler


    I seem to be getting errors when using a CompressHandler in conjunction with a NotFoundHandler. In the following example my 404's don't work at all and the browser's just dumping a "This site can’t be reached" error to the screen. No error messages or stack traces coming from Go either :/

    If I comment out r.NotFoundHandler or h2 := handlers.CompressHandler(h1) then it works.

    package main
    import (
    func main() {
        r := mux.NewRouter()
        r.HandleFunc("/", IndexHandler).Methods("GET")
        r.HandleFunc("/test", TestHandler).Methods("GET")
        r.NotFoundHandler = http.HandlerFunc(NotFoundHandler)
        h1 := handlers.CombinedLoggingHandler(os.Stdout, r)
        h2 := handlers.CompressHandler(h1)
        http.ListenAndServe("localhost:"+os.Getenv("PORT"), h2)
    func NotFoundHandler(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "404 - Not Found")
    func IndexHandler(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello, World!")
    func TestHandler(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Looks good!")
    enhancement help wanted 
    opened by wayneashleyberry 19
  • Loggers don't support the http.Flusher interface

    Loggers don't support the http.Flusher interface

    Spotted this goofing around trying to replace go-restful with a more minimal stack, noticed that here https://github.com/gorilla/handlers/blob/master/handlers.go#L66-L90 there's no support for flushing the buffer if it's supported, would it be accepted as a PR if I would send it ?

    opened by leehambley 17
  • [bug] Request URL Host not set in ProxyHeaders handler

    [bug] Request URL Host not set in ProxyHeaders handler

    When using X-Forwarded-Host header from a reverse proxy, the handler correctly sets r.Host (r is the http.Request), but leaves r.URL.Host unset. This causes some issues with some libraries (eg httprouter) which expects to do something like r.URL.String() to recover the original HTTP(S) request URL.

    Versions Go version: 1.13.4 package version: v1.4.2 (8a3748a)

    Steps to Reproduce Set up a reverse proxy which sends X-Forwarded-Host (such as Traefik) and try to print r.URL.String(). The URL that is built is missing the host part.

    Expected behavior The ProxyHeaders handler should set r.URL.Host as already does for r.Host

    Code Snippets

    // Setup an HTTP server with Go and ProxyHeaders handler
    // Assume a request like https://example.org/page
    // Assume that the reverse proxy is sending headers:
    // X-Forwarded-Host: example.org
    // X-Forwarded-Proto: https
    func pageHandler(w http.ResponseWriter, r *http.Request) {
       // Inside an handler function
       // this should print https://example.org/page
       // instead it prints https:///page
    opened by Enrico204 13
  • [feature] Ability to print stack trace as log

    [feature] Ability to print stack trace as log

    Is your feature request related to a problem? Please describe. We are using recovery handler with stack trace. However, as per https://github.com/gorilla/handlers/blob/master/recovery.go#L89, stack trace is only printed to stdout.

    Describe the solution you'd like As we are logging everything as json, having raw stdout for stack trace is not ideal. It will be great to have ability to print stack trace as log.

    Describe alternatives you've considered

    opened by sayboras 13
  • Proposed enhancements

    Proposed enhancements

    CORSHandler CacheHandler


    GZipHandler come to mind. For the later there is an example here: https://github.com/the42/schoolcalc/blob/master/webzapfen/webzapfen.go#L611

    However, ideally, Handlers would be stackable.

    opened by the42 13
  • Bugfix for reusing CORS() configuration with multiple handlers

    Bugfix for reusing CORS() configuration with multiple handlers

    I was running into a weird issue where my re-using of the CORS handler would lead to the wrong handler being called by my mux, and tracked it down to this bug. I noted that in comparably-configured middleware, like CSRF, the factory should set the handler inside the closure.

    This branch very simply does just that (+ I added a test, which might be overkill).

    opened by saranrapjs 11
  • Added RecoveryHandler

    Added RecoveryHandler

    Good Afternoon! This handler provides the capability to recover from a panic while logging and sending an HTTP 500 error. This follows closely with the negroni recovery middleware.

    Take care, Nicholas

    opened by njohns-grovo 11
  • [feature] Configure CORS middleware to allow all headers

    [feature] Configure CORS middleware to allow all headers

    Is your feature request related to a problem? Please describe.

    I would like the ability to configure the CORS middleware to allow all headers.

    Describe the solution you'd like

    The handlers.AllowedHeaders() function could support "*", which would signal that all headers should be allowed. This is how AllowedOrigins() works, so it would look exactly the same (i.e. handlers.AllowedOrigins([]string{"*"}), and handlers.AllowedHeaders([]string{"*"}))

    I'd be happy to make a pull request if this is something you'd accept.

    enhancement stale 
    opened by deliahu 10
  • CORS 403 Forbidden

    CORS 403 Forbidden

    Hi there,

    I've an issue using CORS, I always get 403 forbidden back on OPTIONS requests.

    router := mux.NewRouter()
    router.HandleFunc("/omniview", rapi.omniview)
    http.ListenAndServe(":8000", handlers.CORS()(router))

    the corresponding CURL call I used to simulate the webcall of my web ui:

    $ curl 'http://dtstest:8000/omniview' -X OPTIONS -H 'Access-Control-Request-Method: POST' -H 'Origin: http://dtstest:8080' -H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7' -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36' -H 'Accept: */*' -H 'Connection: keep-alive' -H 'Access-Control-Request-Headers: content-type' --compressed --verbose
    * STATE: INIT => CONNECT handle 0x600057538; line 1429 (connection #-5000)
    * Added connection 0. The cache now contains 1 members
    * STATE: CONNECT => WAITRESOLVE handle 0x600057538; line 1465 (connection #0)
    *   Trying
    * TCP_NODELAY set
    * STATE: WAITRESOLVE => WAITCONNECT handle 0x600057538; line 1546 (connection #0)
    * Connected to dtstest ( port 8000 (#0)
    * STATE: WAITCONNECT => SENDPROTOCONNECT handle 0x600057538; line 1598 (connection #0)
    * Marked for [keep alive]: HTTP default
    * STATE: SENDPROTOCONNECT => DO handle 0x600057538; line 1616 (connection #0)
    > OPTIONS /omniview HTTP/1.1
    > Host: dtstest:8000
    > Access-Control-Request-Method: POST
    > Origin: http://dtstest:8080
    > Accept-Encoding: gzip, deflate
    > Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7
    > User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36
    > Accept: */*
    > Connection: keep-alive
    > Access-Control-Request-Headers: content-type
    * STATE: DO => DO_DONE handle 0x600057538; line 1695 (connection #0)
    * STATE: DO_DONE => WAITPERFORM handle 0x600057538; line 1822 (connection #0)
    * STATE: WAITPERFORM => PERFORM handle 0x600057538; line 1837 (connection #0)
    * HTTP 1.1 or later with persistent connection, pipelining supported
    < HTTP/1.1 403 Forbidden
    < Date: Thu, 30 Aug 2018 10:23:55 GMT
    < Content-Length: 0
    < Content-Type: text/plain; charset=utf-8
    * STATE: PERFORM => DONE handle 0x600057538; line 2008 (connection #0)
    * multi_done
    * Connection #0 to host dtstest left intact
    * Expire cleared

    What am I doing wrong there? If I do handlers.CORS()(router) before actually setting the routes the requests work (though, r.Body seems to be empty then)

    router := mux.NewRouter()
    router.HandleFunc("/omniview", rapi.omniview)
    http.ListenAndServe(":8000", router)
    question stale 
    opened by STiAT 10
  • CompressHandler: Write on hijacked connection error

    CompressHandler: Write on hijacked connection error

    If the ResponseWriter I pass to handlers.CompressHandler support http.Hijacker gets hijacked, I'll often see this error come out of my server:

    2015/08/25 09:20:41 server.go:1934: http: response.Write on hijacked connection

    I believe this is caused by the deferred Close calls on the gzip/flat Writer's. The documentation for both says that calling Close will flush any pending data, which might generate calls to Write. I believe the fix is to set a flag if Hijack is called on the connection, and only call Call on the gzip/flat Writer if the connection was not hijacked.

    help wanted stale 
    opened by nwidger 10
  • OPTIONS in Allow for MethodHandler

    OPTIONS in Allow for MethodHandler

    MethodHandler supports OPTIONS, but it's not included in Allow.


    allow := []string{http.MethodOptions}

    In case of 405, client should know OPTIONS is an option.

    opened by bakz 0
  • [question] upgrade httpsnoop

    [question] upgrade httpsnoop

    Describe the problem you're having

    I am using multiple dependencies, some using github.com/felixge/[email protected] Would it be possible to upgrade httpsnoop to 1.0.3? As far as I can tell, there are no breaking changes. …


    Go version: go version go1.19 linux/amd64

    package version: 3e030244b4ba0480763356fc8ca0ade6222e2da0

    "Show me the code!"

    go work sync
    go: version constraints conflict:
    	github.com/honeycombio/[email protected] requires github.com/felixge/[email protected], but github.com/felixge/[email protected] is requested
    	github.com/letsencrypt/[email protected] requires github.com/felixge/[email protected], but github.com/felixge/[email protected] is requested
    	github.com/sigstore/[email protected] requires github.com/felixge/[email protected], but github.com/felixge/[email protected] is requested

    "Possible solution"

    Upgrade httpsnoop using go get -u github.com/felixge/httpsnoop.

    opened by malt3 0
  • Incorrect regex in `forRegex`

    Incorrect regex in `forRegex`

    While auditing some internal code for a common mistake made in regex patterns, we discovered a vendored copy of this line:


    The line currently reads

    	forRegex = regexp.MustCompile(`(?i)(?:for=)([^(;|,| )]+)`)

    It was likely intended to read

    	forRegex = regexp.MustCompile(`(?i)(?:for=)([^;, ]+)`)

    however, even that is not correct according to rfc7239. If we wish to follow the RFC, then the forRegex should be defined as

    	forRegex = regexp.MustCompile(`(?i)(?:for=)(?:([-!#$%&'*+.^`|~\w]+)|"((?:[\t \x21-\x27\x2A-\x5B\x5D-\x7E\x80-\xFF]|\\[\t -~\x80-\xFF])+)")`)

    and in that case processing that uses forRegex will need to decide whether the first or second capture group matched and, in the case where the second capture group matched, do the appropriate replacement to remove backslashes.

    opened by fizbin 0
  • [feature] Basic Auth handler

    [feature] Basic Auth handler

    How about to add a basic auth handler? This is still a good option for 90% of APIs. Unfortunately the golang doesn't provide it out of the box. This leads to problems because developers starts to write their own which may not be not secure and fast. Or devs may start to use some auth library which may be configured not properly and again become vulnerable. Even while there may be a separate libraries for this I think it may be good option to have it in the library so users will have it with less dependencies.

    It's questionable how feature rich it should be. I think it must be plain simple and focused on performance. Just as a starter but also because other more feature rich (and slow) libraries exists. E.g. no password hashing: for API credentials this not needed because you can simply reset credentials.


    • Here I wrote myself but I don't like it anymore for few minor reasons: https://github.com/stokito/go-http-server-basic-auth/blob/master/auth_handler.go
    • Most popular library https://github.com/abbot/go-http-auth
    • Some popular gist that many users just copy and paste https://gist.github.com/elithrar/9146306 It's mentioned in the first googled StackOverflow topic :) It's written by the @elithrar
    • Many others libs but none seems good to me https://pkg.go.dev/search?q=basic+auth
    • One of them looks easy to use https://github.com/99designs/basicauth-go/blob/2a93ba0f464d/basicauth.go
    • Prometheus also has basic auth handler with BCrypt support https://github.com/prometheus/exporter-toolkit/blob/master/web/handler.go#L105

    If you think that it may be useful to add the basic auth handler then I may rework my version to be more useful but still easy to use and send a PR.

    opened by stokito 0
  • [question] Does handler add AllowedOrigins * header by default?

    [question] Does handler add AllowedOrigins * header by default?

    Describe the problem you're having

    A clear and concise description of what the bug is. The HTTPS server uses handler config something like this without specifying AllowedOrigins,

    Handler: handlers.CORS(handlers.AllowedHeaders([]string{header1, header2}),

    There is a webserver in front of the backend code which adds a Access-Control-Allow-Origin header. Now I get 2 Access-Control-Allow-Origin headers on the UI, one set by the webserver and the other as access-control-allow-origin: *. Does handlers add * as a default header if not set? I don't see that in the handlers code, but wanted to still verify. …


    Go version: go version go1.17.10 package version: run git rev-parse HEAD inside the repo github.com/gorilla/handlers v1.5.1 …

    "Show me the code!"

    A minimal code snippet can be useful, otherwise we're left guessing!

    Hint: wrap it with backticks to format it

    opened by harshkolhatkar 0
  • v1.5.1(Sep 12, 2020)

    🔊 v1.5.1 fixes an issue with the CompressHandler introduced in v1.5.0 that would break compression of some responses. We strongly recommend you upgrade to v1.5.1.


    • Fix compression of *os.Files. (#197) @muirdm
    Source code(tar.gz)
    Source code(zip)
  • v1.5.0(Aug 22, 2020)

    ⚠ v1.5.1 fixes an issue with the CompressHandler introduced in v1.5.0 that would break compression of some responses. We strongly recommend you upgrade to v1.5.1.

    This release improves how handlers manages existing http.ResponseWriters that are already wrapped with a Pusher or other extensions. It will no longer break existing implementations thanks to the changes made in #193.


    • Use httpsnoop to wrap ResponseWriter. (#193) @muirdm
    • skip compression on upgrade connection (#187) @benitogf
    • Use got-want style so mutation test can be performed easily with corr… (#184) @uudashr
    • [compress] Vary: Accept-Encoding must always be set (#175) @dunglas
    • Cleanup CompressHandlerLevel (#173) @fharding1
    Source code(tar.gz)
    Source code(zip)
  • v1.4.2(Jul 23, 2019)

    This release fixes an issue with hijacked requests that could lead to temp directory mis-use, as well as minor documentation changes.


    • docs: fix missing CircleCI badge (#166) @elithrar
    • Drop accept-encoding header when supported (#157) @klingtnet
    • ProxyHeaders: mention X-Forwarded-Host in the docs (#165) @dunglas
    • Cleanup properly after hijacking a request (#164) @mmussomele
    Source code(tar.gz)
    Source code(zip)
  • v1.4.1(Jul 9, 2019)

    This release adds Go Modules support, among other minor changes (below) ⚡️


    • Create release-drafter.yml (#163) @elithrar
    • Create config.yml (#161) @elithrar
    • Fix formatting & go vet issues (#162) @elithrar
    • Added go.mod file (#149) @arunpoudel
    • Implement http.Pusher interface for compressResponseWriter (Go >= 1.8) (#138) @inliquid
    • Update and rename stale to stale.yml (#136) @elithrar
    • Add stalebot config (#135) @elithrar
    • [cors] add OPTIONS status code + fix function typo (#132) @commit-master
    Source code(tar.gz)
    Source code(zip)
  • v1.4.0(Jul 29, 2018)

    Adds the ability to register a custom log formatter for HTTP logging, and addresses a CORS middleware bug.

    CHANGELOG 7e0847f added ability to register custom log formatter (#131) 6257a58 Fix typo in cors.go (#127) 13a38d2 [bugfix] Handle CORS pre-flight request in middleware (#112) 2b8556b Revert "Add Vary header when allowedOrigins is * (#114)" (#122) 9327cfd Add Vary header when allowedOrigins is * (#114)c5874fa distinguish between explicit and implicit star (#118)

    Source code(tar.gz)
    Source code(zip)
  • v1.3.0(Nov 1, 2017)

    • Fixes a security issue where Access-Control-Allow-Origin would reflect the Origin header in the request, which has different (and worse) security vs. returning an explicit "*". Thanks to @ejcx for reporting and fixing.


    9066371 [bugfix] Don't return the origin header when configured to * (#116)

    Source code(tar.gz)
    Source code(zip)
  • v1.2.1(May 23, 2017)

    • Fixes a bug with loggers that did not call WriteHeader (a4043c6)
    • Adds support for the http.Pusher interface (for HTTP/2 Server Push) (356173f)


    a4043c6 use http.StatusOK as initial value for responseLogger.status (#103) 13d7309 README.md: Add sourcegraph badge 6d39a51 Merge pull request #97 from nwidger/master 602b326 (Combined)LoggingHandler: Add tests for http.Push support 356173f (Combined)LoggingHandler: Add Go 1.8 http.Pusher support

    Source code(tar.gz)
    Source code(zip)
  • v1.2(Jan 24, 2017)

    3a5767c Merge pull request #94 from pavelnikolov/recovery-logger-interface-instead-of-struct 3fda98c Use logger interface in recovery handler (#92) e1b2144 [docs] Add note about the CompressHandler and TLS traffic (#90) a577578 travis.yml: add go1.7 801d6e3 [bugfix] Add ProxyHeaders support for X-Forwarded-Proto (#79) 8e3f298 Add ProxyHeaders support for X-Forwarded-Proto. af3022d [feature] Support X-Forwarded-Host (#75) d3ca879 Support X-Forwarded-Host 66e6c6f Merge pull request #72 from gorilla/elithrar/ci-allow-tip-failures aeb4f8e [ci] Allow CI failures on tip.

    Source code(tar.gz)
    Source code(zip)
  • v1.1(Mar 11, 2016)

    We're now tagging releases, something that was long overdue. gorilla/handlers has strict API compatibility guarantees, excepting any security issues, but we understand that being able to vendor specific versions is a useful feature.

    Source code(tar.gz)
    Source code(zip)
Gorilla Web Toolkit
Gorilla is a web toolkit for the Go programming language that provides useful, composable packages for writing HTTP-based applications.
Gorilla Web Toolkit
A Go middleware that stores various information about your web application (response time, status code count, etc.)

Go stats handler stats is a net/http handler in golang reporting various metrics about your web application. This middleware has been developed and re

Florent Messa 587 Nov 25, 2022
Go http.Hander based middleware stack with context sharing

wrap Package wrap creates a fast and flexible middleware stack for http.Handlers. Features small; core is only 13 LOC based on http.Handler interface;

go-on - web toolkit in Go 59 Apr 5, 2022
Minimalist net/http middleware for golang

interpose Interpose is a minimalist net/http middleware framework for golang. It uses http.Handler as its core unit of functionality, minimizing compl

James Pirruccello 296 Sep 27, 2022
Lightweight Middleware for net/http

MuxChain MuxChain is a small package designed to complement net/http for specifying chains of handlers. With it, you can succinctly compose layers of

Stephen Searles 210 Nov 27, 2022
Idiomatic HTTP Middleware for Golang

Negroni Notice: This is the library formerly known as github.com/codegangsta/negroni -- Github will automatically redirect requests to this repository

null 7.3k Nov 30, 2022
A tiny http middleware for Golang with added handlers for common needs.

rye A simple library to support http services. Currently, rye provides a middleware handler which can be used to chain http handlers together while pr

InVision 98 Sep 27, 2022
Simple middleware to rate-limit HTTP requests.

Tollbooth This is a generic middleware to rate-limit HTTP requests. NOTE 1: This library is considered finished. NOTE 2: Major version changes are bac

Didip Kerabat 2.3k Dec 2, 2022
OpenID Connect (OIDC) http middleware for Go

Go OpenID Connect (OIDC) HTTP Middleware Introduction This is a middleware for http to make it easy to use OpenID Connect. Currently Supported framewo

Xenit AB 68 Nov 27, 2022
Go HTTP middleware to filter clients by IP

Go HTTP middleware to filter clients by IP

cristaltech 4 Oct 30, 2022
Chi ip banner is a chi middleware that bans some ips from your Chi http server.

Chi Ip Banner Chi ip banner is a chi middleware that bans some ips from your Chi http server. It reads a .txt file in your project's root, called bani

null 1 Jan 4, 2022
Painless middleware chaining for Go

Alice Alice provides a convenient way to chain your HTTP middleware functions and the app handler. In short, it transforms Middleware1(Middleware2(Mid

Justinas Stankevičius 2.7k Dec 5, 2022
URL Rewrite middleware for gin

Url Rewrite middleware for gin Example In this exable these urls use the same route http://localhost:1234/test-me http://localhost:1234/index.php/test

Lucian I. Last 3 Sep 15, 2022
A customized middleware of DAPR.

A customized middleware of DAPR.

Gatty 1 Dec 24, 2021
Gin middleware for session.

wsession Gin middleware for session management with multi-backend support: cookie-based Redis memstore Usage Start using it Download and install it: g

null 0 Jan 9, 2022
Fiber middleware for server-timing

Server Timing This is a Fiber middleware for the [W3C Server-Timing API] based on mitchellh/go-server-timing

Vlad Fratila 0 Feb 6, 2022
Go package for rate limiter collection

rlc A rate limiter collection for Go. Pick up one of the rate limiters to throttle requests and control quota. RLC Slider TokenBucket RLC RLC is a rat

Alex Xu 15 Jul 6, 2021
echo-http - Echo http service

echo-http - Echo http service Responds with json-formatted echo of the incoming request and with a predefined message. Can be install directly (go get

Umputun 12 Dec 4, 2022
Composable chains of nested http.Handler instances.

chain go get github.com/codemodus/chain Package chain aids the composition of nested http.Handler instances. Nesting functions is a simple concept. I

Code Modus 65 Sep 27, 2022
Add interceptors to GO http.Client

mediary Add interceptors to http.Client and you will be able to Dump request and/or response to a Log Alter your requests before they are sent or resp

Here Mobility SDK 82 Nov 17, 2022