【问题标题】:conditionally use a middleware depending on request parameter express根据请求参数 express 有条件地使用中间件
【发布时间】:2014-01-21 23:51:42
【问题描述】:

我正在尝试根据请求查询参数来决定要使用的中间件。

在主模块中我有这样的东西:

app.use(function(req, res){
  if (req.query.something) {
    // pass req, res to middleware_a
  } else {
    // pass req, res to middleware_b
  }
});

middleware_amiddleware_b 都是 express 应用程序,它们本身是由 express() 函数创建的,而不是常规的中间件函数 (function(req, res, next))

找不到办法

【问题讨论】:

  • 你的代码有什么问题?作为快速维护者,我建议您这样做。
  • @JonathanOng 问题是middleware_amiddleware_b 都是由express() 创建的对象,而不是常规的中间件函数,所以我不能真正传递req,res,在它们旁边。 ..
  • express 应用程序本身就是中间件。是的,你可以。
  • @JonathanOng 怎么样?你能示范一下吗?当我尝试执行middleware_a(req, res, next) 之类的操作时,它告诉我该对象不是函数
  • 听起来你做错了什么。你能发布一个完整的例子吗

标签: node.js express


【解决方案1】:

connect/express“中间件”没有什么神奇之处:它们只是函数——你可以像调用任何其他函数一样调用它们。

所以在你的例子中:

app.use(function(req, res, next){
  if (req.query.something) {
    middlewareA(req, res, next);
  } else {
    middlewareB(req, res, next);
  }
});

也就是说,可能有更优雅的方式来构建分层快递应用程序。查看TJ's video

【讨论】:

  • 就是这样。我的应用程序与 TJ 的视频相同。所以 middleware_a 和 middleware_b 实际上是对象而不是函数,所以我不能真正将 req, res, next 传递给它们。 Express 知道区分这两者并在将其中任何一个传递给中间件时处理它们
【解决方案2】:

我知道这个问题很老了,但我想分享我的解决方案。我通过创建一个返回带有回调的中间件的函数来解决这个问题。

示例中间件:

function isAdminUser(callback){
    return function(req, res, next){
        var userId = callback(req);
        // do something with the userID
        next();
    }
}

那么你可以在express router对象中做如下操作

app.use(isAdminUser(function(req){
    return req.body.userId
    });

【讨论】:

  • 这是一种优雅的方式,如果我没有找到更好的方式,我想使用它
  • 应该是req 而不是resfunction(req){ return req.body.userId }
【解决方案3】:

我不会使用该中间件 - 而是在中间件 A 和 B 中检查任何内容:

//Middleware A
app.use(function(req, res){

  // If it doesn't match our condition then send to next middleware
  if (!req.query.something) {
    next();
  } else {
    // We're good - let this middleware do it's thing
    ...
    next();
   }
});

与中间件 B 相同

//Middleware B
app.use(function(req, res){

  if (req.query.something) {
    ...
});

【讨论】:

    【解决方案4】:

    如果您来到这里希望像我一样在条件中间件(例如护照或会话)下使用第 3 方中间件,您可以这样做:

    app.use((req, res, next) => {
        // your condition
        if (req.url !== 'no-session') {
          // Your middleware
          session()(req, res, next);
        } else {
          next();
        }
      })
    

    这只会在满足条件时触发会话。您必须将 (req, res, next) 作为参数发送给第二个函数,它总是返回以连接中间件。这应该适用于任何中间件,无论是您自己的还是第三方的。

    【讨论】:

    • 这是正确的!我想在这个答案之后有条件地做passport.authenticate('jwt', { session: false }) 我所做的是return passport.authenticate('jwt', { session: false })(req, res, next)
    【解决方案5】:

    我知道我在这个帖子上有点晚了,但你可以使用这个插件 Express Conditional Tree Middleware.

    它允许您组合多个异步中间件。 具体来说,您可以创建两个代表中间件的类(middleware_a、middleware_b),并在将驻留在这些类中的 applyMiddleware 方法中返回一个由您的中间件函数创建的 Promise 或带有您的中间件结果的自定义已解析 Promise再次运行。

    然后在您的主 js 文件中,您可以根据需要创建一个链接器来有条件地组合这些中间件!查看文档了解更多信息,查看代码后会更清楚。

    【讨论】:

    • 现在看起来是一个正确的答案。我回溯了我的标志并删除了我的(现在不相关的)cmets。
    • 完美!谢谢你让我再次知道,我在这里很新:)
    【解决方案6】:

    我也有同样的需求,所以我创建了一个包装器来创建条件中间件。

    const conditionalMiddleWare = function(condition) {
      return function(middleware) {
        return function(req, res, next) => {
          if (
            (typeof condition == 'boolean' && condition) ||
            (typeof condition == 'function' && condition(req, res, next))
          ) {
            return middleware(req, res, next);
          }
          next();
        };
      }
    }
    

    您可以将其与布尔值一起使用

    // Only use this middleware on production environment
    forProduction = conditionalMiddleWare(server.settings.env === 'production');
    server.use(forProduction(auth.connect()));
    

    您可以根据要求动态决定使用功能

    // Only use this middleware when it's not the `/api/` folder that is requested
    const forNotApi = conditionalMiddleWare(function(req) {
     return !req.path.startsWith('/api/');
    });
    server.use(forNotApi(express.static(rootDir)));
    

    希望对你有帮助!

    【讨论】:

      【解决方案7】:

      看起来你可能错过了诀窍。 每个中间件都是一个请求处理程序。首先查看第一个请求处理程序,然后查看下一个,然后是下一个,依此类推。

      中间件大致如下所示:

      function myFunMiddleware(request, response, next) {
      // Do stuff with the request and response.
      // When we're all done, call next() to defer to the next middleware.
      next();
      }
      

      我建议您将代码修改为类似的内容。

      app.use(function(request, response, next) {
        if (request.url == "/") {
        response.writeHead(200, { "Content-Type": "text/plain" });
        response.end(".. Any custom msg..\n");
       // The middleware stops here.
        } 
        else {
        next();
      }});
      

      请通过这个tutorial,我相信你会对使用中间件有一个很好的了解。祝您编码愉快。

      【讨论】:

        【解决方案8】:

        对于异步函数,您可以这样做:

        
        // Generic middleware style function.
        const processData = async(data) => {
          // Do some processing.
          const processedData = await something(data);
          if (response.error) {
            return [{message: "There was an error"}];
          }
          return [ false, processedData ]
        }
        
        
        const routeMiddleware = async(req, res, next) => {
          if (req.body.data.property === 'a') {
            const [ err, processedData] = await processData(req.body.data);
            if (err) next(err);
            return res.json({ message: 'Successfully processed', processedData});
          } else {
            return res.json({ message: 'Not processed'});
          }
        }
        
        

        这种模式的优点:

        • processData() 函数可以在应用程序的其他地方重复使用
        • 易读
        • 使用异步/等待

        在异步函数调用周围包装一个 try/catch 块也可能是一个好主意,或者使用 @awaitjs/express。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-09-15
          • 2023-01-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-06-07
          相关资源
          最近更新 更多