Gorilla mux custom middleware
Asked Answered
H

5

38

I am using gorilla mux for manage routing. What I am missing is to integrate a middleware between every request.

For example

package main

import (
    "fmt"
    "github.com/gorilla/mux"
    "log"
    "net/http"
    "strconv"
)

func HomeHandler(response http.ResponseWriter, request *http.Request) {

    fmt.Fprintf(response, "Hello home")
}

func main() {

    port := 3000
    portstring := strconv.Itoa(port)

    r := mux.NewRouter()
    r.HandleFunc("/", HomeHandler)
    http.Handle("/", r)

    log.Print("Listening on port " + portstring + " ... ")
    err := http.ListenAndServe(":"+portstring, nil)
    if err != nil {
        log.Fatal("ListenAndServe error: ", err)
    }
}

Every incoming request should pass through the middleware. How can I integrate here a midleware?

Update

I will use it in combination with gorilla/sessions, and they say:

Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler as or else you will leak memory! An easy way to do this is to wrap the top-level mux when calling http.ListenAndServe:

How can I prevent this scenario?

Hazel answered 5/10, 2014 at 16:5 Comment(1)
For those who landed here: gorilla/mux now has inbuilt middleware handling: github.com/gorilla/mux#middlewareCook
A
73

Just create a wrapper, it's rather easy in Go:

func HomeHandler(response http.ResponseWriter, request *http.Request) {

    fmt.Fprintf(response, "Hello home")
}

func Middleware(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        log.Println("middleware", r.URL)
        h.ServeHTTP(w, r)
    })
}
func main() {
    r := mux.NewRouter()
    r.HandleFunc("/", HomeHandler)
    http.Handle("/", Middleware(r))
}
Acne answered 5/10, 2014 at 16:30 Comment(2)
Thanks for this, h.ServeHTTP(w, r) this part is what I was missing. They don't make it very clear how to directly call a Handler.Greig
You can also use r.Use(Middleware) to register middleware.Keli
C
26

Mux has an official way of doing it look on this example

// a regular middleware
func Middleware(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // do stuff before the handlers
        h.ServeHTTP(w, r)
        // do stuff after the hadlers

    })
}

// if you want to pass data into the middleware 
func Middleware2(s string) mux.MiddlewareFunc {
    return func(h http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            // do stuff
            fmt.Println(s)
            h.ServeHTTP(w, r)
        })
    }
}

func main() {
    router := mux.NewRouter()


    router.Use(Middleware)
    //you can apply it to a sub-router too
    subRouter := router.PathPrefix("/sub_router/").Subrouter()
    subRouter.Use(Middleware2("somePrams"))
    // Add more middleware if you need, call router.Use Again
    router.Use(Middleware3, Middleware4, Middleware5)

    _ = http.ListenAndServe(":80", router)
}

the official doc on the mux website

Cuprite answered 9/9, 2019 at 20:15 Comment(0)
V
13

I'm not sure why @OneOfOne chose to chain router into the Middleware, I think this is slight better approach:

func main() {
    r.Handle("/",Middleware(http.HandlerFunc(homeHandler)))
    http.Handle("/", r)
}

func Middleware(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    h.ServeHTTP(w, r)
})}
Vermination answered 28/10, 2015 at 23:17 Comment(2)
This approach was exactly what I was looking for — a nested Handle with middleware. Thank you!Wording
This is pretty much the same thing as @OneOfOne's answerEphedrine
S
6

If you want to apply a middleware chain to all routes of a router or subrouter you can use a fork of Gorilla mux https://github.com/bezrukovspb/mux

subRouter := router.PathPrefix("/use-a-b").Subrouter().Use(middlewareA, middlewareB)
subRouter.Path("/hello").HandlerFunc(requestHandlerFunc)
Shadshadberry answered 16/4, 2016 at 19:12 Comment(3)
Thanks dude! This express.js middleware style was exactly what I was looking forBordiuk
Middleware Use is builtin now in gorilla muxHairsplitting
@ozy you mean router.Use(), but it's good to use a subrouter, so that middleware can be applied different places.Ephedrine
M
0

You might consider a middleware package such as negroni.

Mavis answered 5/10, 2014 at 16:16 Comment(2)
When I would use it gorilla/sessions, it would not happen memory leak?Hazel
I can't edit since Suggested edit queue is full. The link does not exist anymore. I want to replace it with a new one negroniReckon

© 2022 - 2024 — McMap. All rights reserved.