http中间件的作用:对请求-响应循环进行了包装,在到达应用程序代码之前扩展请求对象或者在响应前后进行修改。
Node的Connect框架对中间件组件定义了一个模型,还定义了一个引擎来运行中间件组件。实际上Express框架实际上是依赖Connect创建而成的。优点:
* 模型简单
* 中间件易于组合和插拔
* 中间件易于定制和优化
* 丰富的中间件
中间件只是一个接受请求和响应对象的函数。下面展示一个简单的示例。先安装connect模块:
npm install connect
创建一个helloworld.js文件:
function helloworld(req,res){
res.end('hello world');
};
module.exports = helloworld;;
创建connect服务器测试中间件
var connect = require('connect');
var http = require('http');
var helloworld = require('./helloworld');
var app = connect();
app.use(helloworld);
http.createServer(app).listen(8080);
中间件函数是可以异步的,当工作结束时,调用一个回调函数,以便让引擎继续工作。示例:创建一个中间件组件,将头部数据引入响应头中。
function writeHeader(name,value){
return function(req,res,next){
res.writeHeader(name,value);
next();
};
}
module.exports = writeHeader;
将这个中间件包含到传入服务器构造函数的中间件堆栈中:
var connect = require('connect');
var helloworld = require('./helloworld');
var writeHeader = require('./writeHeader');
var app = connect();
app.use(writeHeader('haha',"hha"));
app.use(helloworld);
app.listen(8080);
启动后访问就可看到响应头中多了个haha而且输出helloworld.
中间件最朴素的原型:
function(req,res,next){
....
}
三个参数分别代表请求对象、响应对象、下一个中间件。如果当前中间件调用了res.end()结束了响应,执行下一个中间件就没有意义了。
中间件的流式处理:
var app = connect();
// Middleware
app.use(connect.staticCache());
app.use(connect.static(__dirname + '/public'));
app.use(connect.cookieParser());
app.use(connect.session());
app.use(connect.query());
app.use(connect.bodyParser());
app.use(connect.csrf());
app.use(function (req, res, next) {
// 中间件
});
app.listen(8080);
Conncet提供use方法用于注册中间件到一个Connect对象的队列中,此队列叫做中间件队列。
在请求来临的时候,依次调用队列中的中间件,直到某个中间件不再调用下一个中间件为止。
必须要有一个中间件调用res.end()方法来告知客户端请求已被处理完成,否则客户端将一直处于等待状态。
app.use()方法接受两个参数,路由信息和中间件函数。路由的作用是过滤不匹配的URL。请求在遇见路由信息不匹配时,直接传递给下一个中间件处理。如果没有传路由则表示所有的请求都会被该中间件处理。
考虑到的一个性能问题是中间队列太长会降低性能。文件上传中间件:
app.use('/upload',connect.multipart({uploadDir:path}));
记录请求:
var connect = require('connect');
var app = connect();
app.use(connect.logger());
app.use(function(req,res){
res.end('helloworld');
});
app.listen(8080);
还可以指定输出日志格式:
app.use(connect.logger('tiny'));
//或者只输出HTTP方法,URI,状态码和响应时间
var format = ':method:url-:status-:response-time ms';
app.use(connect.logger(format));
处理错误:
app.use(function(req,res,next){
next(new Error('hey'));
});
app.use(connect.errorHandler());
提交静态文件:
app.use(connect.static(_dirname+'/public'));
app.use(function(req,res){
res.end('hello world');
});
app.listen(8080);
静态文件服务器会在public目录中查找文件,如果找到,文件就会被提交,中间件链也会被中断。启动后访问localhost:8080/pic.jpg。public目录下如果有则浏览器会呈现图像。
将查询字符串设置到请求上,以便下一个中间件可以使用。
app.use(connect.query());
app.use(function(req,res){
res.end(JSON.stringify(req.query));
});
请求主体解析中间件在请求对象上提供了一个body属性,而且能够识别内容类型并对其正确的解码。例如appliction/json类型。
app.use(connect.bodyParser());
ap.use(funcition(req,res){
res.end(JSON.stringify(req.body));
});
app.listen(8080);
app.use(connect.cookieParser());
app.use(function(req,res){
res.end(JSON.stringify(req.cookies));
});
会话默认使用内存储存器,实际应用应该使用外部持久存储器。
var format = require('util').format;
app.use(connect.query());
app.use(connect.cookieParser('加密字符串'));
app.use(connect.session({
cookie:{maxAge:24*60*60*1000}
}));
app.use(function(req,res){
for(var name in req.query){
req.session[name] = req.query[name];
}
res.end(format(req.session));
});
还有很多其他可用的中间件。可以到connect的github主页去看。