什么是Node.js的Connect,Express和“中间件”?

  • 回答 (2)
  • 关注 (0)
  • 查看 (275)

尽管知道JavaScript非常好,但我很困惑Node.js生态系统中的这三个项目究竟做了什么。这是像Rails的机制吗?有人可以解释吗?

Lonely永夜Lonely永夜提问于
人生的旅途辣鸡前端回答于

如果你有想写属于自己的express.js中间件的想法,很可能你知道express.js实际上就是一个Connect(附带额外的特性),如果你还不知道它,或许你应该先静心地了解更多的Connect知识。

如果你已经知道Connect是什么,并且想为它写一个中间件,那么你来对地方了。我将给展示怎样和express.js一起使用你自己崭新的中间件。

在我们写中间间之前,我们需要知道它是什么。

通常情况下,一个链接服务器的请求在HTTP response被生成前要经过一些方法。在连接期间这些方法按照惯例被称为“中间件”。这就是它,非常简单。

使用Express.js或Connect,你可能遇到req,res和next对象们,中间件方法做它们的事情,如果需要并把req,res和next传给下一个线性排列的方法。这就是中间件的工作机制。

中间件函数作为插件被放到请求流中(request flow),通过在Connnect里使用 connect.use(),或在express中使用app.use().看看这个Connect的服务例子:

[javascript] view plain copy
var http = require('http');  
var connect = require('connect');  
  
var app = connect();  
app.use(function(req, res) {  
    res.end('Hello!');  
});  
  
http.createServer(app).listen(3000);  

这仅有一个中间件,每一个向服务器的请求,它仅仅打印出“hello!”。

尽管中间件都是函数,可以通过connect.use()方法把它作为插件使用,为了代码的重用和整洁,最好将它们开发成一个node.js的模块,而不是在connect.use()里定义一个方法。

让我们创建一个禁止IP地址的中间件模块,我们称它为 "ipban",创建一个名叫ipban.js的文件,里面存有以下内容:

[javascript] view plain copy
// list of banned IPs  
var banned = [  
'127.0.0.1',  
'192.168.2.12'  
];  
  
// the middleware function  
module.exports = function() {  
      
    return function(req, res, next) {  
        if (banned.indexOf(req.connection.remoteAddress) > -1) {  
            res.end('Banned');  
        }  
        else { next(); }  
    }  
      
};  

现在,修改下链接服务的代码来使用我们的中间件:

[javascript] view plain copy
var ipban = require('./ipban.js');  
var app = connect();  
app.use(ipban());  
app.use(function(req, res) {  
    res.end('Hello!');  
});  

运行app并且尝试在浏览器里加载。嗙!被禁止了!运行app并且尝试在浏览器里加载。嗙!被禁止了!

接下来呢?一个自定义的中间件模块需要返回一个方法,这个方法理想情况下接受 req,res或next三个参数。

你可能已经注意到当初始化一个中间件是大部分都接受配置选项。那么我们使ipban能够这样做也是自然的。通过传递“on”或者”off“,ipban 将会有效或者无效。

修改ipban.js文件:

[javascript] view plain copy
// list of banned IPs  
var banned = [  
'127.0.0.1',  
'192.168.2.12'  
];  
  
// middleware enabled or not  
var enabled = true;  
  
// the middleware function  
module.exports = function(onoff) {  
      
    enabled = (onoff == 'on') ? true : false;  
      
    return function(req, res, next) {  
        if (enabled && banned.indexOf(req.connection.remoteAddress) > -1) {  
            res.end('Banned');  
        }  
        else { next(); }  
    }  
      

};

同样,使用方法也需要改变:

[javascript] view plain copy
app.use(ipban('off'));  

重启app,在浏览器里加载,不再被禁止!

如果你的中间件不是http请求的终点,确保调用next(),否则你将以一个挂起的应用而结束。

如果用express.js来使用这个中间件,我们就要这样做:

[javascript] view plain copy
var ipfilter = require('./ipfilter');  
app.configure(function(){  
    app.use(ipfilter('on'));  
...  

注意:中间件的顺序是非常重要的,它能启动也能断开你应用。

秋之夕颜清念念不忘,必有回响回答于

我刚开始学习Express的时候,在app.js中发现app.use,当时比较困惑。

app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));

这里其实就是定义使用了中间件(Middleware)。Express框架实际上是依赖Connect创建的,这里的use方法是Conncet提供的,它用来注册一个中间件到Connect 中间件队列。

什么是中间件?

我的理解是这样的,中间件就是类似于一个过滤器的东西,在客户端和应用程序之间的一个处理请求和响应的的方法。

什么是Connect?

Connect 是Node.js中的一个模块,可以用来创建中间件的一个框架,它自身已经包装了Node的HTTP模块的Server以及Server的req和res的对象。它干的活其实就是处理请求,然后响应客户端或是让下一个中间件继续处理,它的原型是这个样子的

function (req, res, next) {
  // 中间件
}

当next回调函数被调用,中间件就完成工作并传递到下一个中间件,如果没其他中间件则进入到应用逻辑继续执行。

下面来写一个简单的脚本,自己注册2个中间件来理解下:

var connect = require('connect'),
    http = require('http');
var app = connect()
    .use(access)
    .use(test);
function access(req,res,next){
    var now = new Date().getHours();
    if(now <13 || now >18){
        res.writeHead(503,{'Content-Type':'text/plain'});
        res.end('下午1点到6点之外禁止访问!');
    }else{
        next();
    }
}
function test(req,res){
    res.writeHead(200,{'Connect-Type':'text/plain'});
    res.end('this is test page');
}

http.Server(app).listen(3000);

这这段代码中,我们注册了2个中间access和test到中间件队列中,这里需要注意的一点就是,Connect是流式处理。通过执行这段代码以后,浏览器访问以下体会吧!

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励