I need to implement case insensitive URL matching in gorilla mux as it is done here for built in mux
I tried to achieve the same using middle-ware like this
router := mux.NewRouter()
router.Use(srv.GetCaseMiddleware())
//GetCaseMiddleware middleware to make match URL case insensitive
func (srv *Server) GetCaseMiddleware() (w mux.MiddlewareFunc) {
var middleware mux.MiddlewareFunc = func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
r.URL.Path = strings.ToLower(r.URL.Path)
next.ServeHTTP(w, r)
})
}
return middleware
}
but still it throws 404 if URL case is changed,is there any way to implement it using gorilla-mux
Unfortunately, as of this writing, middleware functions are invoked after URL matching in gorilla/mux.
Mux supports the addition of middlewares to a Router, which are executed in the order they are added if a match is found, including its subrouters.
I would suggest going with the example in the link you provided.
e.g.
func CaselessMatcher(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
r.URL.Path = strings.ToLower(r.URL.Path)
next.ServeHTTP(w, r)
})
}
Then, just wrap your multiplexer.
r := mux.NewRouter()
//...
handler := CaselessMatcher(r)
It's actually not bad IMO.
Related
Im using Gorilla/Mux for routing and want to serve the React SPA regardless of the URL path.
func main() {
fmt.Println("server running...")
hub := newHub()
go hub.run()
router := mux.NewRouter()
router.HandleFunc("/api/create", Api)
router.HandleFunc("/api/getpoll", Api)
router.HandleFunc("/api/update", Api)
router.HandleFunc("/sockets/{id}", func(w http.ResponseWriter, r
*http.Request) {
Socketme(hub, w, r)
})
// router.HandleFunc("/{rest:.*}", emberHandler)
router.PathPrefix("/").HandlerFunc(serveFile)
log.Fatal(http.ListenAndServe(":5000", router))
}
func serveFile(w http.ResponseWriter, r *http.Request) {
http.FileServer(http.Dir("./public/build")).ServeHTTP(w, r)
}
Dont want Go to give 404s the Spa should be handling these routes.
The Router exports a NotFoundHandler field which you can set to your custom handler.
router := mux.NewRouter()
router.NotFoundHandler = MyCustom404Handler
So you could do something like:
router.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "./public/build/index.html")
}))
so that it always serves your index page when it would normally return a 404
So I couldnt find any workable solutions to this. So I ended up taking a different approach using mux.Subrouter found here Static file server in Golang using gorilla/mux
I'm building an application using the Micro Service Architecture.
On the gateway, I do want to route requests to the correct endpoints.
But, the endpoint are now known at runtime and needs to be configured in the DB.
Below if the code to get the router.
func getRouter() *mux.Router {
r := mux.NewRouter()
r.Use(dynamicRouteMiddleware)
return r
}
The middleware itself is this:
func dynamicRouteMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Println("Error")
})
}
However, the "Error" is never printed.
It's only printed when I put a handler for '/'
How can I create middleware without handlers?
It's called "middleware" because it's supposed to put your Handler in the "middle". It receives the input before your Handler, and receives the output of your Handler.
Inherently, to have your middleware work, you are required to have at least one Handler. Preferably you may just use this functionality that you need in the Handler rather than middleware.
On the middleware, you need call the next handler so all incoming requests will proceed to the destination route.
func dynamicRouteMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Println("Error")
next.ServeHTTP(w, r) // <------- this one
})
}
You can register any routes as you want, but in the very end make sure the r object used as handler of / route.
r.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("test"))
})
r.HandleFunc("/test/12", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("test 12"))
})
r.HandleFunc("/about-us", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("about us"))
})
http.Handle("/", r)
http.ListenAndServe(":8080", nil)
When you access /test, /test/12, or /about-us; the Error will still be printed.
Previously it's not printed because you don't proceed to the next handler. The code next.ServeHTTP(w, r) is mandatory in your case.
I am building a Go web application that supports various middleware functions when handling routing. I'm trying to stick to net/http as much as possible and was wondering how I might accomplish this without using middleware libraries like negroni.
Essentially what I would like to do is to be able to provide a slice of middleware functions, say one for logging, one for checking for a valid JWT, and then finally the handler to handle the request.
I am able to do this with negroni fairly simply by defining the following struct:
// Route ..
type Route struct {
Method string
Path string
Middleware []negroni.Handler
Handler http.HandlerFunc
}
and then defining a route like:
var commonRoutes = []Route{
{
Method: "GET",
Path: "/info",
Middleware: []negroni.Handler{negroni.HandlerFunc(middleware.CheckCache), negroni.HandlerFunc(middleware.Authenticated), negroni.NewLogger()},
Handler: handlers.APIInfo,
},
}
Finally when I boot up my server, I import the list of routes and register them like so:
for _, r := range routes {
handler := append(r.Middleware, negroni.Wrap(r.Handler))
router.Handle(r.Path, negroni.New(handler...)).Methods(r.Method)
}
And this works perfectly.
Any idea how I might be able to do this with just the standard net/http signature and way of defining middleware handlers that look like this:
http.Handle("/", middlewareOne(middlewareTwo(finalHandler)))
Thank you :)
func Auth(n http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("Start")
n.ServeHTTP(w, r)
log.Printf("End")
})
}
func processReq(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Success"))
}
func main() {
handler := http.HandlerFunc(processReq)
http.Handle("/",Auth(handler))
http.ListenAndServe(":8000", nil)
}
can be done using http.handler
Simple. You define each handler like so:
// So I don't have to type it over and over...
type HTTPHandler func(w http.ResponseWriter, r *http.Request)
func Handler1(next HTTPHandler) HTTPHandler {
return func(w http.ResponseWriter, r *http.Request){
// Do stuff
if next != nil {
next(w, r)
}
}
}
// Handler2 ... HandlerN defined in the same basic way.
// Chaining:
http.Handle("/", Handler1(Handler2(nil)))
Each handler takes the next handler and returns a closure that does whatever you want plus calling the next handler. If you need lots of these it may make sense to write a helper similar to this one:
func MakeHandler(worker, next HTTPHandler) HTTPHandler {
return func(w http.ResponseWriter, r *http.Request){
// Maybe have to worker return an error and do standard error
// handling here? Could simplify your code some depending on
// what you are doing.
worker(w, r)
if next != nil {
next(w, r)
}
}
}
This is part of my main function that I use for my end points
r := mux.NewRouter()
r.StrictSlash(true)
r.HandleFunc("/", test)
r.HandleFunc("/feature/list/", a.FeatureListHandler)
log.Fatal(http.ListenAndServe(":8080", r))
but when I curl localhost:8080/feature/list I get
<a hef="/feature/list">Moved Permanently</a>
However, when I curl localhost:8080/feature/list/ I get my json.
How do I make it so that both routes will return the json I want.
From the docs, it seems this is the expected behaviour for when StrictSlash is true:
http://www.gorillatoolkit.org/pkg/mux#Router.StrictSlash
Perhaps you can set it to false and then define both routes separately?
r.StrictSlash(false)
r.HandleFunc("/feature/list", a.FeatureListHandler)
r.HandleFunc("/feature/list/", a.FeatureListHandler)
I use the following middleware to deal with this
func suffixMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// remove the trailing slash from our URL Path if it's not root
if r.URL.Path != "/" {
r.URL.Path = strings.TrimSuffix(r.URL.Path, "/")
}
// Call the next handler, which can be another middleware in the chain, or the final handler.
next.ServeHTTP(w, r)
})
}
Then you pass your router through such as:
(suffixMiddleware(router))
There seem to be all sorts of examples of using a HandlerFunc closure similar to this one: http://codegangsta.gitbooks.io/building-web-apps-with-go/content/controllers/README.html
However I can't get it to work with a subrouter. Example:
func MyHandler(renderer *render.Render) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
renderer.HTML(rw, http.StatusOK, "subroute/index", nil)
})
}
func main() {
renderer := render.New(render.Options{Layout: "base"})
router := mux.NewRouter().StrictSlash(false)
router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
...
})
subroutes := router.Path("/subroute").Subrouter()
subroutes.Methods("GET").HandlerFunc(MyHandler(renderer))
http.Handle("/", router)
log.Println("Listening...")
http.ListenAndServe(":3000", nil)
}
Gives me this error:
cannot use MyHandler(renderer) (type http.Handler) as type func(http.ResponseWriter, *http.Request) in function argument
Any insights into what I'm doing wrong?
The HandlerFunc method on Route expects to be passed a function, as the error message indicates. If instead you have an http.Handler, call Handler instead:
subroutes.Methods("GET").Handler(MyHandler(renderer))
Or alternatively, have your MyHandler function return the handler function directly rather than wrapping it as an http.Handler. Which option you choose is going to be a matter of style, and depend on the rest of your program.