首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >让回调阻塞线程

让回调阻塞线程
EN

Stack Overflow用户
提问于 2016-08-05 13:36:52
回答 1查看 44关注 0票数 0

我正在使用ExpressJS中间件检查数据库中的用户ip并停止响应用户,如果在过去的一个小时内有超过7次失败的登录,我在数据库连接之前使用检查'/‘,如果一切正常,则不会向数据库发送垃圾邮件。但事实证明,当中间件访问数据库并在回调中执行检查时,第一个else中的代码会运行。这是我的中间件:

代码语言:javascript
复制
// check for failed logins from this ip in db
// if allowed number exceeded - stop responding
app.use(function (req, res, next) {
if(req._parsedUrl.pathname === '/') {
    MongoClient.connect(databaseUri || 'mongodb://localhost:27017/dev', function (err, db) {
        assert.equal(err, null);
        var failedLogins = db.collection('FailedLogins');
        failedLogins.find({ip: req._remoteAddress}).toArray(function (err, results) {
            assert.equal(err, null);
            console.log('db check');
            // if ip is in FailedLogins collection
            if (results.length) {
                // if there are more than 7 logins and they haven't expired
                if (results[0].failedLoginsNum >= 7 && parseInt(results[0].expiration) >= parseInt(Date.now())) {
                    res.end();
                } else {
                    next();
                }
            } else {
                next();
            }
        });
    });
} else {
    console.log('next');
    next();
}
});

这是控制台输出:

代码语言:javascript
复制
db check
GET / 200 20.117 ms - -
next
GET /favicon.ico 200 207.559 ms - 1353
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-08-05 16:01:11

这是预期的行为,因为建立了比db连接更早接收的第二个请求,并且完成了查找查询。

首先,你不想在每次请求时都创建新的连接,这是一个糟糕的做法。

考虑下一段代码:

dbProvider.js

代码语言:javascript
复制
'use strict';

const MongoClient = require('mongodb').MongoClient;
const CONNECTION_PATH = 'mongodb://localhost:27017/dev';

module.exports.init = cb => {
  MongoClient.connect(CONNECTION_PATH, (err, db) => {
    module.exports.db = db;
    cb(err, db);
  });
};

index.js

代码语言:javascript
复制
'use strict';

const express = require('express');
const app = express();

const dbProvider = require('./dbProvider');
const PORT = 8888;

dbProvider.init((err, db) => {
  if(err) {
    console.error(err);
    process.exit(1);
  }

  app.listen(PORT, () => console.log(`Listening on port ${PORT}`));
});

在index.js中,我们一直等到连接建立,然后才会侦听HTTP请求。下一步是登录,所以如果你想限制登录尝试,我建议使用简单的中间件。

index.js已修改

代码语言:javascript
复制
'use strict';

const express = require('express');
const app = express();

const dbProvider = require('./dbProvider');
const PORT = 8888;

dbProvider.init((err, db) => {
  if(err) {
    console.error(err);
    process.exit(1);
  }

  app.listen(PORT, () => console.log(`Listening on port ${PORT}`));
});

// middlewares

function checkAuth(req, res, next) {
  // here check if userId in cookie and match to db record or check token
  if (req.authenticated()) {
    return next();
  } else {
    return res.send(401); // Respond "Unauthorized"
  }
}

function checkLoginAttempts(req, res, next) {
  let failedLogins = dbProvider.db.collection('FailedLogins');
  failedLogins.find({ip: req._remoteAddress}).toArray(function (err, results) {
    if(err) {
      console.error(err);
      return res.status(500).end();
    }
    console.log('db check');

    if(!results.length) return next();

    // if ip is in FailedLogins collection
    // if there are more than 7 logins and they haven't expired
    if (results[0].failedLoginsNum >= 7 && parseInt(results[0].expiration) >= parseInt(Date.now())) {
      res.status(401).send('The maximum number of login attempts has been reached. Please try again in 1 hour.');
    } else {
      next();
    }
  });
}

// routes

app.use('/yourLoginEndPoint', checkLoginAttempts, (req, res) => {
  // login process, set userId as cookie value or create token
});

app.use('/anyOtherEndPoint', checkAuth, (req, res) => {
  // here you sure that user is authenticated
});

如果有任何问题,请告诉我

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38781810

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档