You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The single stack middleware system of express seems to be a source of confusion for some developers. This is a proposal to isolate the middleware stack in a router from other routers mounted on the same app.
Current behavior:
A middleware defined without a path on router A will get executed for requests matching in router B.
Proposed behavior:
A middleware defined without a path on router A should get executed only for requests matching in router A, and not on any other router.
The current behavior of app.use(), which executes its middleware for all the requests to the app would remain the same and should be used for defining global middleware.
If a request comes in at /foo/bar, the proposed behavior is that if Router A matches, no other router's middleware should be executed, which I don't think would be desirable in the above situation. Does this imply that maybe the most specific match would be the router that gets executed (in this case Router B) - if so I feel like it would also not be desirable to ignore A.
This proposal is limited to the behavior of pathless routes defined in routers.
Hi @hacksparrow, there is no concept at all for "pathless routes" in Express or this router. Just because the path argument is optional doesn't actually make not specifying it intrinsically different from specifying '/' at the path argument. This sounds like there is now a per-requisite on come up with "pathless routes" and how those are defined and work.
This proposal is limited to the behavior of routes defined in routers without specifying a path.
Right, but that's the problem: unless there is another change before this to the concepts in the router, app.use(fn) must behave identically to app.use('/', fn) especially because there are many configuration-based builders on top of this module that always provide that argument since it is promised to work in an identical way.
Another major problem with the proposal as-is is request URL rewriting. A middleware is absolutely allowed to alter the URL and method of a request, and processing will continue with the new URL. Because of this, we cannot even understand if a request will match any given route until all prior middleware are executed.
Agree with @dougwilson . There's no way to know if you are "inside" of a router when executing middleware. I also agree that single stack can be confusing for developers that haven't experienced it before.
Looking at the original ticket #2760, I'm not entirely sure a solution would work. If you have multiple Routers mounted at the same spot, the middleware will be executed for all of them until some piece of middleware exits the chain (usually a route). You could isolate the routers explicitly by doing something like the following:
Instead of appending all of the Router's middleware to the global stack, you instead append a single function.
This function checks if the path matches the Router, if it does it executes the Router's "sub"-stack.
This doesn't solve the problem either, because middleware is already implicitly isolated because each middleware is checked against Router.path + middleware.path.
The real problem I think is that people are expecting it to work like such: if a route is matched in a Router, then execute everything in the router. You could modify what I wrote above to change the match to also loop through all the routes in a router and see if one matches.
If this wouldn't be feasible, I think my proposal at #35 would be a reasonable middle ground. It kind of simulates the effects of isolated middleware for route-handlers only. For #2760 it would be the workaround so "foo" doesn't have to be repeated many times.
@QuotableWater7, I do not believe so. I believe the current thinking on this would be, Express does not need to support every feature or configuration, but it should make it simple to swap in parts to get what you need.
So in this case, I would recommend using a router which supports the feature you need (router level isolation). If this means forking this to provide your features, go for it. The router is decoupled from much of express as long as you implement the interface.
IMHO, we should probably close this issue since it has not seen progress and is quite a big change in how the router works.
OMG I was facing the same issue, it took me over an hour to get here. This is definitely not the expected behavior and causes lot of confusion. Has there been any progress?
Reacted by Kian Gregory, George Mihailov and fliccione
Activity
frankxw commentedon Feb 29, 2016
What if two Routers are mounted like such:
/foo/foo/barIf a request comes in at
/foo/bar, the proposed behavior is that if Router A matches, no other router's middleware should be executed, which I don't think would be desirable in the above situation. Does this imply that maybe the most specific match would be the router that gets executed (in this case Router B) - if so I feel like it would also not be desirable to ignore A.tunniclm commentedon Feb 29, 2016
@demaius You could have it so
app.use('/foo', fn)would apply to both routers, butfooRouter.use(fn)would only apply tofooRouterand notbarRouter.hacksparrow commentedon Feb 29, 2016
@demalus the behavior would remain the way it is currently for that case - the router loaded earlier will get to process the request object first.
This proposal is limited to the behavior of pathless routes defined in routers.
dougwilson commentedon Feb 29, 2016
Hi @hacksparrow, there is no concept at all for "pathless routes" in Express or this router. Just because the
pathargument is optional doesn't actually make not specifying it intrinsically different from specifying'/'at thepathargument. This sounds like there is now a per-requisite on come up with "pathless routes" and how those are defined and work.hacksparrow commentedon Feb 29, 2016
@dougwilson I didn't mean pathless literally, it was more about the interface when omitting the path parameter. Sorry about the confusion.
So, clarifying myself here:
This proposal is limited to the behavior of routes defined in routers without specifying a path.
dougwilson commentedon Feb 29, 2016
Right, but that's the problem: unless there is another change before this to the concepts in the router, app.use(fn) must behave identically to app.use('/', fn) especially because there are many configuration-based builders on top of this module that always provide that argument since it is promised to work in an identical way.
hacksparrow commentedon Feb 29, 2016
How about "behavior of routes defined in routers without specifying a path or at the root path"?
dougwilson commentedon Feb 29, 2016
Another major problem with the proposal as-is is request URL rewriting. A middleware is absolutely allowed to alter the URL and method of a request, and processing will continue with the new URL. Because of this, we cannot even understand if a request will match any given route until all prior middleware are executed.
hacksparrow commentedon Feb 29, 2016
Agreed.
frankxw commentedon Feb 29, 2016
Agree with @dougwilson . There's no way to know if you are "inside" of a router when executing middleware. I also agree that single stack can be confusing for developers that haven't experienced it before.
Looking at the original ticket #2760, I'm not entirely sure a solution would work. If you have multiple Routers mounted at the same spot, the middleware will be executed for all of them until some piece of middleware exits the chain (usually a route). You could isolate the routers explicitly by doing something like the following:
This doesn't solve the problem either, because middleware is already implicitly isolated because each middleware is checked against Router.path + middleware.path.
The real problem I think is that people are expecting it to work like such: if a route is matched in a Router, then execute everything in the router. You could modify what I wrote above to change the match to also loop through all the routes in a router and see if one matches.
frankxw commentedon Feb 29, 2016
If this wouldn't be feasible, I think my proposal at #35 would be a reasonable middle ground. It kind of simulates the effects of isolated middleware for route-handlers only. For #2760 it would be the workaround so "foo" doesn't have to be repeated many times.
QuotableWater7 commentedon Apr 19, 2019
Does anyone know if this kind of feature ever got anywhere? The existing behavior was totally unexpected and derailed a refactor I was working on 😒
wesleytodd commentedon May 21, 2019
@QuotableWater7, I do not believe so. I believe the current thinking on this would be, Express does not need to support every feature or configuration, but it should make it simple to swap in parts to get what you need.
So in this case, I would recommend using a router which supports the feature you need (router level isolation). If this means forking this to provide your features, go for it. The router is decoupled from much of express as long as you implement the interface.
IMHO, we should probably close this issue since it has not seen progress and is quite a big change in how the router works.
karlismelderis commentedon Nov 5, 2020
would be really nice to support this:
Aditya-ds-1806 commentedon Apr 5, 2021
OMG I was facing the same issue, it took me over an hour to get here. This is definitely not the expected behavior and causes lot of confusion. Has there been any progress?
Refactors routers to include path