mux
mux copied to clipboard
[question]
Hello guyes, i would like to know how to make internal redirect. What i mean is: Let's say i have some middlware and two handler. One fo /first/{key} - handler1 and /second/{value} --handler2
So let's assume the chaing is middleware + handler: LogMiddle->AuthMiddle->handler1 and the same is for second one.
Now i want to call handler2 from handler1 avoiding middleware and changingrequest
I try to do somethink like that:
func handler1 (w http.ResponseWriter, req *http.Request){
newPath:= "/second"+ mux.Vars(req)["key"]
req.URL.Path = newPath
match := mux.RouteMatch{}
isMatched := Router.Match(req, &match)
if isMatched {
match.Route.GetHandler().ServeHTTP(w, req)
}
}
So it matches /second/{key}
But inside the handler2 when i try
val, _ := mux.Vars(req)["value"]
i have nothing. (Vars still has only "key" variable)
So i'm searching a way to do it write without external redirection. (Try to avoid auth middleware).
The best example is to creete several handlers, and one of them is: /main/{urlToCall} and then, this main handler takes urlToCall and choose the right one. Is there some proper way?
I'm not able to understand your use-case. In my opinion your use-case is incorrect because — let's assume we got two routes
1. /first/{key} — FirstHandler
2. /second/{value} — SecondHandler
Since these two routes are different then I dont' think route /first/{key}
will give any useful information regarding /second/{value}
.
Let's assume for a moment if it works somehow and you're constructing routing (route2) based on the route 1 /first/{key}
information then inside your FirstHandler right thing to do is redirect. If there is no such things and you don't want to implement redirect then why not to directly call SecondHandler inside the FirstHandler? Something like below
func FirstHandler(w http.ResponseWriter, r *http.Request) {
SecondHandler(w, r)
}
func SecondHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Gorilla!\n"))
}
Middleware are applied globally on the router level. If there are several URLs like mentioned /main/{urlToCall}
possibly this can we worked using nested routes. I would recommend to go through the comment https://github.com/gorilla/mux/issues/445#issuecomment-463220765
If this comment answers what you're looking for, I request you to close the issue.
Thank you
Hi amustaque97!
Thank you for your reply! Let me be more clear.
Let's assume i have a route which serves presigned url.
/presigned/{urlStructure}
{urlStructure} key contains info about url which should be called, about call rules, timestamp and so on. So base on {urlStructure} i check if everythink is ok in terms of access and then i want to choose right route to call presigned path.
Let's assume for a moment if it works somehow and you're constructing routing (route2) based on the route 1 /first/{key} information then inside your FirstHandler right thing to do is redirect
I cannot use redirect directly because there is auth procedure in middleware and i have no opportunity to get token for that , so i need to avoid calling middlware it's why i do not use direct redirect.
so let's go futher, now i have all info about presigned url and want to call it directly.
If there is no such things and you don't want to implement redirect then why not to directly call SecondHandler inside the FirstHandler? Something like below
It would be a way and it's something what i try to do but: Mux.Vars has been calculated for first path and i would like to recalculate if for new path, but i do not know how. (That's what i met alredy in this approach. if there is a way to recalculate mux.Vars in terms of changed request, please let me know, it would solve my case)
func handler1 (w http.ResponseWriter, req *http.Request){
newPath:= "/second"+ mux.Vars(req)["key"]
req.URL.Path = newPath
match := mux.RouteMatch{}
isMatched := Router.Match(req, &match)
if isMatched {
match.Route.GetHandler().ServeHTTP(w, req) <---- there are mux.Vars for old request, it's not has been recalculating for new request, and it's my problem.
}
}
Guys, any advice? Would be really glad to any advice in this
If the second handler being called is only ever going to be called from another handler, then why is it a handler in the first place? If my understanding is correct, handler2
is only ever called from handler1
(not seeing the verbatim code makes me draw this assumption). So, if that is the case, why make handler2
an HTTP handler? Why not another function that can be called with the necessary request data parsed from handler1
then given to handler2
.
Andrewpillar, thank you for reply!
If the second handler being called is only ever going to be called from another handler
The second handler can be called directly (as http handler), or indirectly from another handler.
Assume it's as a service with a lot of routes and the service also has the "God route" which could allow access to any route avoiding auth procedure in middleware
- request (/first/{key}) -> middlware -> firstHandler(w http.ResponseWriter, req *http.Request) -> getting {key} -> call needed process function - fine
- request (/God/{routeToCall})-> GodHandler(w http.ResponseWriter, req *http.Request) -> getting {routeToCall} -> (assume routeToCall contains "call first request with
newKey
" ) -> construct new request (/first/newKey) and here i should direclty call firstHandler(w http.ResponseWriter, req *http.Request) and that's what i'm doing with the new request avoiding middleware and then i cannot get {key} from request inside first handler, there is still only {routeToCall} variable. So i try to find right way to do it.
Assume it's as a service with a lot of routes and the service also has the "God route" which could allow access to any route avoiding auth procedure in middleware
Without wider context it will be hard to give a definitive answer. But based on this alone it sounds like you want to implement some kind of superuser route that will allow a superuser to view the page as another user? If this is the case, then the best approach would be fiddling around with the cookie/session data containing this information to allow for this superuser functionality.
Again, without wider context, or an explicit example that pertains to your code, I don't think anyone could provide a good solution.
Without wider context it will be hard to give a definitive answer. But based on this alone it sounds like you want to implement some kind of superuser route that will allow a superuser to view the page as another user?
Something like that, it's presigned url. So when we call "God rout" we put signed {urlParams} where insude are acess rules, time till when it's accessable, the target rout itself and so on. So cookie/sessio not a way i think. The user get presigned url, and then can give it somewhere to make some procedure in service
No way to restruct mux.Vars(req) for new request?
No way to restruct mux.Vars(req) for new request?
I'm not getting time because of release at my office. I actually wanted to check method mux.BuildVarsFunc before adding any comment here.
I actually wanted to check method mux.BuildVarsFunc before adding any comment here.
Waiting for that, thank you !
@Fyria30, thank you so much for waiting so long. I'm afraid I don't think there is any other way to achieve internal redirection. You can follow your current implementation.
Thank you for your patience. Have a nice day ahead.
@amustaque97 Thank you for your time! But the problem is i have no any implementation now. So BuidVarsFunc can not be used for this task?
@amustaque97 Thank you for your time! But the problem is i have no any implementation now. So BuidVarsFunc can not be used for this task?
No, I don't think so.
@amustaque97 Did not find better way but it works fine. So i added two public methods in the mux packet to have opportunity to rebuild request vars.
func requestWithVars(r *http.Request, vars map[string]string) *http.Request {
ctx := context.WithValue(r.Context(), varsKey, vars)
return r.WithContext(ctx)
}
func requestWithRoute(r *http.Request, route *Route) *http.Request {
ctx := context.WithValue(r.Context(), routeKey, route)
return r.WithContext(ctx)
}
func RequestWithVars(r *http.Request, vars map[string]string) *http.Request {
return requestWithVars(r, vars)
}
func RequestWithRoute(r *http.Request, route *Route) *http.Request {
return requestWithRoute(r, route)
}
And then i use it like:
...
func test (router *mux.Router, w http.ResponseWriter, req *http.Request) error{
requestedkey, _ := mux.Vars(req)["requestedkey"]
newPath := "/anotherpath/" + requestedkey
req.URL.Path = newPath
req.RequestURI = newPath
var match mux.RouteMatch
isMatched := router.Match(req, &match)
if isMatched {
req = mux.RequestWithVars(req, match.Vars)
req = mux.RequestWithRoute(req, match.Route)
match.Route.GetHandler().ServeHTTP(w, req)
return
} else {
return
}
...
Do not you want MR to make those methods public also? Would it make any sense for you ?
Hi @Fyria30, sorry for the late reply. Even I implemented similar changes in my local to achieve your requirements. I'm afraid to tell you that this is a rare case and it is not safe to update vars inside the handler. So I would say we should close this issue 🙂