我有一个节点应用程序,就像防火墙/调度程序一样放在其他微服务前面,它使用如下所示的中间件链:
...
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);
上面解决了我的问题,如果这是关于我想知道的,只需发布。