从快速中间件中排除路由



我有一个节点应用程序,就像防火墙/调度程序一样放在其他微服务前面,它使用如下所示的中间件链:

...
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这样的过滤器?

即使 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 内部使用的路径到正则表达式模块。

更新 :- 在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);
        }
    };
};

建立在@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"));

抱歉无法添加为评论。

你也可以通过在 req.originalURL 上放置一个条件来跳过这样的路由:

app.use(function (req, res, next) {
    if (req.originalUrl === '/api/login') {
    return next();
    } else {
         //DO SOMETHING
    }

我成功地使用了这个正则表达式:/^/(?!path1|pathn).*$/ .

这里有很多很好的答案。不过,我需要一个稍微不同的答案。

我希望能够从所有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()));

您可以定义一些路由,如下所示。

 app.use(//((?!route1|route2).)*/, (req, res, next) => {
    //A personal middleware
    //code
    next();//Will call the app.get(), app.post() or other
 });

就我而言,我使用了部分尚未发布的答案来覆盖原始app.use

const unless = ( route, middleware ) => {
    return ( req, res, next ) => {
        if ( req.originalUrl.startsWith( route + '/' ) ) {
            return next();
        } else {
            return middleware( req, res, next );
        }
    };
};
const filteredRoute = '/myapi';  // Route to filter and subroute
const origUse = app.use;
app.use = function ( ...callbacks ) {
    if ( !callbacks.length ) throw new Error( '.use() method requires at least one function' );
    if ( typeof callbacks[0] ==='string' ) {
        if ( !( callbacks.length -1 ) ) throw new Error( '.use() method requires at least one function' );
        const route = callbacks.shift();
        for ( let i = 0; i < callbacks.length; i++ ) {
            origUse.call( this, route, unless( filteredRoute, callbacks[i] ) );
        }
    } else {
        for ( let i = 0; i < callbacks.length; i++ ) {
            origUse.call( this, unless( filteredRoute, callbacks[i] ) );
        }
    }
};

以下是使用 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;

我实现这一点的方法是为特定的路径设置一个中间件,如下所示

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);
此处

提供了快速文档

改进了

@Geelie的答案,增加了类型:

import {Request, Response, NextFunction, Handler} from "express";
const unless = (middleware: Handler, ...paths: RegExp[]): Handler => {
  return function (req: Request, res: Response, next: NextFunction) {
    const pathCheck = paths.some(path => path.test(req.path));
    pathCheck ? next() : middleware(req, res, next);
  };
};
app.use(unless(redirectPage, new RegExp("/user/login"), new RegExp("/user/register")));
我想

确保如果我点击除 POST/user/login 之外的所有其他方法,那么我应该得到 404 - 未找到对于POST/user/signup也是如此

router.post("/signup", userSignup).all("*", (req, res) => res.sendStatus(404));
router.post("/login", userLogin).all("*", (req, res) => res.sendStatus(404));
router.get("/:id", getParticularUser);
router.patch("/:id", editUserDetails);

上面解决了我的问题,如果这是关于我想知道的,只需发布。

最新更新