首页 > 解决方案 > 在 NodeJs 中间件中使用异步函数的问题

问题描述

当我尝试从中间件代码中的 Redis DB 加载黑名单的初始数据时遇到问题。由于数据库请求需要一些时间,它开始失败。

下面是我的代码,当应用程序通过app.use(blacklist.blockRequests());.

当我尝试使函数异步时,我收到错误消息new TypeError('app.use() requires a middleware function')

副作用之一是我的数组在再次调用时为空。

blockRequests: function() {
  this.read();
  this.logEvent('info', 'There are ' + this.blacklist.length + ' address(es) on the blacklist');
  var self = this;

  var interceptor = function(request, response, next) {
    var ip = request.headers['x-forwarded-for'] || request.connection.remoteAddress;

    if (self.isInBlacklist(ip)) {
      self.logEvent('warn', 'Rejecting request from ' + ip + ', path and query was ' + request.originalUrl);
      response.status(403).send();
    } else {
      next();
    }
  }

  return interceptor;
},

这是我的read()功能代码:

read: function() {
  try {
    // get all records with prefix block:: from redis
    redis.redis.keys('block::*', function (err, reply) {
      // reply is null when the key is missing
      if(err){}
      else {
        this.blacklist = []

        for (let i = 0; i < reply.length; i++) {
          let ipInt = reply[i].substring(7)
          let ipStr = ipToInt(ipInt).toIP()
          this.blacklist.push(ipStr)             
        }
      }   
    });
  } catch (error) {
    if (error) {
      this.blacklist = [];
    }
  }
}

标签: javascriptnode.js

解决方案


如果您尝试进行blockRequests()异步,那么它将开始返回一个承诺,并且您不能直接在app.use(). 因为那样你会这样做app.use(somePromise),而 Express 会犹豫,因为你必须向它传递一个函数引用,而不是一个承诺。

相反,您将不得不使用.then()orawait获取返回值,这是您可以使用的函数app.use()

如果您在此处显示更大的调用上下文(例如您从哪里调用blockRequests()),那么我们可以提供更多关于更完整解决方案的想法。

这是一个关于如何做到这一点的概念性想法:

blockRequests: function() {
  const self = this;
  const interceptor = function(request, response, next) {
    const ip = request.headers['x-forwarded-for'] || request.connection.remoteAddress;

    if (self.isInBlacklist(ip)) {
      self.logEvent('warn', 'Rejecting request from ' + ip + ', path and query was ' + request.originalUrl);
      response.status(403).send();
    } else {
      next();
    }
  }
  return interceptor;
},

read: function() {
    // get all records with prefix block:: from redis
    return new Promise((resolve, reject) => {
        redis.redis.keys('block::*', (err, reply) => {
            if (err) {
                this.blacklist = [];
                reject(err);
            } else {
                this.blacklist = [];
        
                for (let i = 0; i < reply.length; i++) {
                  let ipInt = reply[i].substring(7)
                  let ipStr = ipToInt(ipInt).toIP()
                  this.blacklist.push(ipStr)             
                }
            }
            this.logEvent('info', 'There are ' + this.blacklist.length + ' address(es) on the blacklist');
            resolve();
        });
    });
}


// register middleware for using blacklist
app.use(blacklist.blockRequests());

// now read the blacklist and when that is in place, then start the server
blacklist.read().then(() => {
   // now we know that blacklist.blacklist is up-to-date

   // start your server here

}).catch(err => {
   console.log("Unable to start server - error in reading blacklist");
   process.exit(1);
});

推荐阅读