接下来介绍一个Connect内置的一些中间件:
static中间件
1.挂载
static允许将任意一个URL匹配到文件系统中任意一个目录。如:将/my-images URL和名为/images的目录对应起来,可以以如下方式进行挂载:
server.use('/my-images', connect.static('/path/to/images'));
2. maxAge
static中间件接收一个名为maxAge的选项,这个选项代表一个资源在客户端缓存的时间。对于一些不经常改动的资源来说,我们可以进行缓存,浏览器就无需每次都去请求它了。
server.use('/js', connect.static('/path/to/bundles', {maxAge: 1000000000000}));
比如,一种Web应用常见的实践方式就是将所有的客户端JavaScript文件都合并到一个文件中,并在文件名中加上修订号。这个时候,就可以设置maxAge选项,让其永远缓存起来。如上述代码。
3. hidden
static接收的另一参数hidden。当hidden值为true时,Connect会托管那些文件名以点(.)开始的在UNIX文件系统中被认为是隐藏的文件:
server.use(connect.static('/path/to/resources', {hidden: true}));
query中间件
使用query中间件,能够通过req.query对象自动获取URL中的查询字符串。如:我们请求url /blog?page=5时,我们获取数据查询字符串 page=5,可以这么使用(req.url变量中存储着URL的值,即 /blog?page=5):
server.use(connect.query);
server.use(function(req, res) {
});
logger中间件
logger中间件将发送进来的请求信息和发送出去的响应信息打印在终端。
它提供了以下四种日志格式:
- default
- dev
- short
- tiny
如:使用dev日志格式,可以通过如下初始化logger中间的方式:
server.use(connect.logger('dev'));
dev是一种精准简短的日志格式,能够提供行为以及性能方面的信息,方便测试Web应用。
logger中间还允许自定义日志输出格式,还能通过动态的req和res来记录头信息。
下面是完整的可用token:
- :req[header](如:req[accept])
- :res[header](如:res[content-length])
- :http-version
- :response-time
- :remote-addr
- :date
- :method
- :url
- :referrer
- :user-agent
- :status
使用如下:
server.use(connect.logger(':method :remote-addr'));
server.use(connect.logger('type is :res[content-type], length is '
+ ':res[content-length] and it took :response-time ms.'));
logger还能够自定义token。如,要给请求Content-Type定义一个简写的:type token,可以采用如下方式:
connect.logger.token('type', function(req, res) {
return req.headers['content-type'];
});
body parser中间件
1.接收POST数据
使用body parse中间件可以接收POST请求的数据,并将数据存储到req.body中。如:
server.use(connect.bodyParser());
server.use(function(req, res) {
});
2.处理上传
bodyParser另一功能就是使用formidable模块,它可以让你处理用户上传的文件。如:
var server = connect(
connect.bodyParser(),
connect.static('static')
);
server.use(function(req, res, next) {
if('POST' == req.method && req.body.file) {
console.log(req.body.file);
fs.readFile(req.body.file.path, 'utf8', function(err, data) {
if(err) {
res.writeHead(500);
res.end('Error!');
return;
}
res.writeHead(200, {'Content-Type': 'text/html'});
res.end([
'<h3>File: ' + req.body.file.name + '</h3>',
'<h4>Type: ' + req.body.file.type + '</h4>',
'<h4>Contents:</h4><pre>' + data + '</pre>'
].join(''));
});
} else {
next();
}
});
3.多文件上传
在input的name属性上加上[],即
<input type="file" name="files[]"/>
<input type="file" name="files[]"/>
这个时候为多文件上传,这时req.body.files就包含了一个数组。
cookie
当浏览器发送cookie数据时,会将其写到cookie头信息中。其数据格式和URL中的查询字符串类似。如:
GET /detail HTTP/1.1
Host: 127.0.0.1
Cookie: key1=value1; key2=value2
Accept: */*
使用cookieParser中间件就可以通过req.cookies对象轻松访问到这些cookie数据:
server.use(connect.cookieParser())
server.use(function(req, res, next) {
// req.cookies.key1 = "value1"
// req.cookies.key2 = "value2"
})
会话(session)
在绝大多数Web应用中,多个请求间共享“用户会话”的概念是非常必要的。它主要通过在浏览器中设置cookie来实现,该cookie信息会在随后所有的请求头信息中被带回到服务器中。
用户登录的案例:
var connect = require('connect'),
users = require('./users'); // 这里直接require了JSON文件,不需要使用module.exports对数据进行暴露
var server = connect(
connect.logger('dev'),
connect.bodyParser(),
connect.cookieParser(),
// 出于安全考虑,在初始化session中间件的时候需要提供secret选项
connect.session({secret: 'my app secret'}),
function(req, res, next) {
if('/' == req.url && req.session.logged_in) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end('Welcome back, <b>' + req.session.name + '</b>.'
+ '<a href="/logout">Logout</a>');
} else {
next();
}
},
function(req, res, next) {
if('/' == req.url && 'GET' == req.method) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end([
'<form action="/login" method="POST">',
'<fieldset>',
'<legend>Please log in</legend>',
'<p>User: <input type="text" name="user"></p>',
'<p>Password: <input type="password" name="password"></p>',
'<button>Submit</button>',
'</fieldset>',
'</form>'
].join(''));
} else {
next();
}
},
function(req, res, next) {
if('/login' == req.url && 'POST' == req.method) {
res.writeHead(200);
if(!users[req.body.user] || req.body.password != users[req.body.user].password) {
res.end('Bad username/password');
} else {
req.session.logged_in = true;
req.session.name = users[req.body.user].name;
res.end('Authenticated!');
}
} else {
next();
}
},
function(req, res, next) {
if('/logout' == req.url) {
req.session.logged_in = false;
res.writeHead(200);
res.end('Logged out!');
} else {
next();
}
}
);
server.listen(3000);
其中users.json文件内容如下:
{
"DreamBoy": {
"password": "123",
"name": "梦小白"
}
}
为了让session能够在生产环境中也正常工作,我们需要通过Redis来实现一个持久化。
Redis session
当我们登录成功后,重启node服务器,然后刷新浏览器,会发现需要重新登录,也就是说session失效或或者说不见了。
原因在于session默认存储在内存中。这意味着session数据存储在内存中时,当进程退出后,session数据自然也就丢失了。
生产环境中,需要使用一种当应用重启后,还能够将session信息持久化存储下来的机制,如Redis。
Redis是一个既小又快的数据库,有一个connect-redis模块使用Redis来持久化session数据,这样就让session驻扎到了Node进程之外。
使用如下(必须要安装好Redis):
var connect = require('connect'),
RedisStore = require('connect-redis')(connect);
使用中间件:
server.use(connect.session({store: new RedisStore, secret: 'my secret'}));
methodOverrid中间件
basicAuth中间件
注:暂不说明。
总结
- 中间件是串行执行的。
- 使用中间件的好处:代码能以此为构建单元进行组织,并且能够获得高复用性。
- Connect是实现了中间件这一思路的模块,它为构建更具表达力的中间件提供了基础架构。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)