从快速中间件中排除路由
Posted
技术标签:
【中文标题】从快速中间件中排除路由【英文标题】:Exclude route from express middleware 【发布时间】:2015-01-22 21:40:27 【问题描述】:我有一个节点应用程序,就像防火墙/调度程序一样位于其他微服务前面,它使用如下中间件链:
...
app.use app_lookup
app.use timestamp_validator
app.use request_body
app.use checksum_validator
app.use rateLimiter
app.use whitelist
app.use proxy
...
但是对于特定的 GET 路由,我想跳过除 rateLimiter 和代理之外的所有路由。他们是一种使用 :except/:only 设置像 Rails before_filter 这样的过滤器的方法吗?
【问题讨论】:
你可以使用 'express-unless' npm 来达到这个目的。 【参考方案1】:即使 expressjs 中没有内置的中间件过滤系统,您至少可以通过两种方式实现这一点。
第一种方法是挂载所有要跳转到正则表达式路径的中间件,而不是包含否定查找:
// Skip all middleware except rateLimiter and proxy when route is /example_route
app.use(/\/((?!example_route).)*/, app_lookup);
app.use(/\/((?!example_route).)*/, timestamp_validator);
app.use(/\/((?!example_route).)*/, request_body);
app.use(/\/((?!example_route).)*/, checksum_validator);
app.use(rateLimiter);
app.use(/\/((?!example_route).)*/, whitelist);
app.use(proxy);
第二种方法,可能更易读和更简洁,是用一个小的辅助函数包装你的中间件:
var unless = function(path, middleware)
return function(req, res, next)
if (path === req.path)
return next();
else
return middleware(req, res, next);
;
;
app.use(unless('/example_route', app_lookup));
app.use(unless('/example_route', timestamp_validator));
app.use(unless('/example_route', request_body));
app.use(unless('/example_route', checksum_validator));
app.use(rateLimiter);
app.use(unless('/example_route', whitelist));
app.use(proxy);
如果您需要比简单的path === req.path
更强大的路由匹配,您可以使用 Express 内部使用的path-to-regexp module。
更新:- 在express 4.17
req.path
中只返回'/',所以使用req.baseUrl
:
var unless = function(path, middleware)
return function(req, res, next)
if (path === req.baseUrl)
return next();
else
return middleware(req, res, next);
;
;
【讨论】:
此处链接的 path-to-regexp 模块已弃用。这是正确的:github.com/pillarjs/path-to-regexp 我知道这很旧,但我想知道为什么有人指出正则表达式已损坏。当路由为/example_route
时,您的正则表达式仍匹配/
,因此不会跳过路由。 @guillaume 在下面给出了正确的几个答案:/^\/(?!path1|pathn).*$/
【参考方案2】:
这里有很多很好的答案。不过我需要一个稍微不同的答案。
我希望能够从所有 HTTP PUT 请求中排除中间件。所以我创建了一个更通用的unless
函数版本,它允许传入谓词:
function unless(pred, middleware)
return (req, res, next) =>
if (pred(req))
next(); // Skip this middleware.
else
middleware(req, res, next); // Allow this middleware.
示例用法:
app.use(unless(req => req.method === "PUT", bodyParser.json()));
【讨论】:
【参考方案3】:我实现这一点的方法是为这样的特定路径设置中间件
app.use("/routeNeedingAllMiddleware", middleware1);
app.use("/routeNeedingAllMiddleware", middleware2);
app.use("/routeNeedingAllMiddleware", middleware3);
app.use("/routeNeedingAllMiddleware", middleware4);
然后像这样设置我的路线
app.post("/routeNeedingAllMiddleware/route1", route1Handler);
app.post("/routeNeedingAllMiddleware/route2", route2Handler);
对于不需要所有中间件的其他特殊路由,我们像这样设置另一个路由
app.use("/routeNeedingSomeMiddleware", middleware2);
app.use("/routeNeedingSomeMiddleware", middleware4);
然后像这样设置相应的路由
app.post("/routeNeedingSomeMiddleware/specialRoute", specialRouteHandler);
这方面的 Express 文档可在 here 获得
【讨论】:
【参考方案4】:这是一个使用path-to-regexp
的示例,正如@lukaszfiszer 的回答所建议的那样:
import RequestHandler from 'express';
import pathToRegexp from 'path-to-regexp';
const unless = (
paths: pathToRegexp.Path,
middleware: RequestHandler
): RequestHandler =>
const regex = pathToRegexp(paths);
return (req, res, next) =>
regex.exec(req.url) ? next() : middleware(req, res, next);
;
export default unless;
【讨论】:
【参考方案5】:基于@lukaszfiszer 的回答,因为我希望排除不止一条路线。 您可以在此处添加任意数量。
var unless = function(middleware, ...paths)
return function(req, res, next)
const pathCheck = paths.some(path => path === req.path);
pathCheck ? next() : middleware(req, res, next);
;
;
app.use(unless(redirectPage, "/user/login", "/user/register"));
抱歉,无法添加为评论。
【讨论】:
很好的答案。应该是解决方案。 我同意这值得更多的支持。简洁明了。 只是将其全部转换为 ES6 和单行:const unless = (middleware, ...paths) => (req, res, next) => paths.some(path => path === req.path) ? next() : middleware(req, res, next);
漂亮的解决方案。如果它接受/users/:id/login
,那就太好了
@EricGuan 您可以通过对路径检查稍作调整来实现这一点。而不是path === req.path
,您可以使用一些逻辑来检查路径的动态部分并将其剥离或忽略。也许正则表达式会做得最好【参考方案6】:
你可以像下面这样定义一些路由。
app.use(/\/((?!route1|route2).)*/, (req, res, next) =>
//A personal middleware
//code
next();//Will call the app.get(), app.post() or other
);
【讨论】:
您好,请为您的答案添加一些解释并格式化您的代码。请参阅***.com/help/formatting 了解更多信息。【参考方案7】:我成功地使用了这个正则表达式:/^\/(?!path1|pathn).*$/
。
【讨论】:
我喜欢这个!但我会尽量不要将它用于负载较重的服务器。我会尝试在路线上省略正则表达式。 RegExp匹配确实很快,但是字符串比较快很多。【参考方案8】:您也可以通过在 req.originalUrl 上设置条件来跳过这样的路线:
app.use(function (req, res, next)
if (req.originalUrl === '/api/login')
return next();
else
//DO SOMETHING
【讨论】:
技术上没有错,但并没有真正涵盖动态路径,例如/:user/stuff
以上是关于从快速中间件中排除路由的主要内容,如果未能解决你的问题,请参考以下文章