1
votes

I'm using Gorilla Mux as my web server.

I define a bunch of routes, but if no route is matched, I want it to serve my index.html file.

func (mgr *ApiMgr) InstantiateRestRtr() *mux.Router {
    mgr.pRestRtr = mux.NewRouter().StrictSlash(true)
    mgr.pRestRtr.PathPrefix("/api/").Handler(http.StripPrefix("/api/",
        http.FileServer(http.Dir(mgr.fullPath+"/docsui"))))

    for _, route := range mgr.restRoutes {
        var handler http.Handler
        handler = Logger(route.HandlerFunc, route.Name)
        mgr.pRestRtr.Methods(route.Method)
          .Path(route.Pattern)
          .Name(route.Name)
          .Handler(handler)
    }

    // Here I want to catch any unmatched routes, and serve my '/site/index.html` file. 
    // How can I do this?

    return mgr.pRestRtr
}
2

2 Answers

2
votes

You don't need to override the 404 behaviour. Use PathPrefix as a catch-all route, adding it after all other routes.

func main() {
    var entry string
    var static string
    var port string

    flag.StringVar(&entry, "entry", "./index.html", "the entrypoint to serve.")
    flag.StringVar(&static, "static", ".", "the directory to serve static files from.")
    flag.StringVar(&port, "port", "8000", "the `port` to listen on.")
    flag.Parse()

    r := mux.NewRouter()

    // Note: In a larger application, we'd likely extract our route-building logic into our handlers
    // package, given the coupling between them.

    // It's important that this is before your catch-all route ("/")
    api := r.PathPrefix("/api/v1/").Subrouter()
    api.HandleFunc("/users", GetUsersHandler).Methods("GET")

    // Serve static assets directly.
    r.PathPrefix("/dist").Handler(http.FileServer(http.Dir(static)))

    // Catch-all: Serve our JavaScript application's entry-point (index.html).
    r.PathPrefix("/").HandlerFunc(IndexHandler(entry))

    srv := &http.Server{
        Handler: handlers.LoggingHandler(os.Stdout, r),
        Addr:    "127.0.0.1:" + port,
        // Good practice: enforce timeouts for servers you create!
        WriteTimeout: 15 * time.Second,
        ReadTimeout:  15 * time.Second,
    }

    log.Fatal(srv.ListenAndServe())
}

func IndexHandler(entrypoint string) func(w http.ResponseWriter, r *http.Request) {
    fn := func(w http.ResponseWriter, r *http.Request) {
        http.ServeFile(w, r, entrypoint)
    }

    return http.HandlerFunc(fn)
}

Shameless plug: I blogged on this here: http://elithrar.github.io/article/vue-react-ember-server-golang/

0
votes
func NewRouter() *mux.Router {
    router := mux.NewRouter().StrictSlash(true)
    routes := client.GetRoutes()
    for _, route := range routes {
        var handler http.Handler
        handler = route.HandlerFunc
        handler = context.ClearHandler(handler)

        router.
            Methods(route.Method).
            Path(route.Pattern).
            Name(route.Name).
            Handler(handler)

    }
    r := OGRouter{router: router}
    router = r.router
    router.NotFoundHandler = http.HandlerFunc(r.NotFoundHandler)
    return router
}

/* Handled mux router drawback of giving 404 in every case i.e if either URI or METHOD
*  is not matched mux router will give 404. So, this case is handled her, if Method will
*  not match we will through 405
 */
func (router *OGRouter) NotFoundHandler(rw http.ResponseWriter, req *http.Request) {

    r := *router.router
    route := r.Get(req.RequestURI)

    if route != nil {
        if req.RequestURI == route.GetName() {

            routeMatch := mux.RouteMatch{Route: route}

            if !route.Match(req, &routeMatch) {
                rw.WriteHeader(http.StatusMethodNotAllowed)
            }
        } else {
            rw.WriteHeader(http.StatusNotFound)
        }
    } else {
        rw.WriteHeader(http.StatusNotFound)
    }
}

type OGRouter struct {
    router *mux.Router
}

Where you are getting 404 you can serve a new page