gogorilla

Gorilla Mux router from inside handler only works once then gives 404 page not found


I'm using Gorilla mux as my router and I'm having a very strange behaviour. On the first request to the server, I get a valid response. But on subsequent requests, I receive a 404 page not found. There are no errors in the console.

My code is pretty straightforward (it can be copy-pasted to test it right out):

package main

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

func main() {
    router := mux.NewRouter()
    router.HandleFunc("/", RootHandler).Name("root")
    http.Handle("/", router)

    log.Println("Listening on port 1337...")
    if err := http.ListenAndServe(":1337", nil); err != nil {
        log.Fatal("http.ListenAndServe: ", err)
    }
}

func RootHandler(w http.ResponseWriter, r *http.Request) {
    content := "Welcome to "
    rootUrl, err := mux.CurrentRoute(r).Subrouter().Get("root").URL()
    if err != nil {
        log.Printf("mux.CurrentRoute(r).Subrouter().Get(\"root\").URL(): ", err)
    }
    response := content + rootUrl.String()
    fmt.Fprintf(w, response)
}

After some code commenting and tests, it seems the following line is the culprit:

rootUrl, err := mux.CurrentRoute(r).Subrouter().Get("root").URL()

This method of getting the router inside the handler using the current request comes from another StackOverflow post: How to call a route by its name from inside a handler?

But for a strange reason, it only works once:

shell-1$ go run servertest.go
2014/10/30 13:31:34 Listening on port 1337...

shell-2$ curl http://127.0.0.1:1337
Welcome to /
shell-2$ curl http://127.0.0.1:1337
404 page not found

As you can see, there are no errors in the console.

Does someone have an idea of why it only works once ?


Solution

  • The problem is Subrouter() isn't made to return the router, but to create one, thus it changes the matcher of the router it is called on, making you lose the handler.

    You could try passing the router to the handler using closures instead.

    func RootHandler(router *mux.Router) func(http.ResponseWriter, *http.Request) {
        return func(w http.ResponseWriter, r *http.Request) {
            ...
        }
    }