创建一个Application对象实例,也就是创建一个Express应用。app对象一般在Express应用的app.js文件中创建,通过app对象,可以实现定向HTTP请求、配置中间件、渲染HTML、配置模板等。
- 创建对象实例
- 属性
- 事件
- 方法
- 4.1 定义路由处理器:
app.all() - 4.2 定义
DELETE请求路由:app.delete() - 4.3 关闭设置:
app.disable() - 4.4 检查设置是否关闭:
app.disabled() - 4.5 开启设置:
app.enable() - 4.6 检查设置是否开启:
app.enabled() - 4.7 设置模块引擎:
app.engine() - 4.8 获取设置值:
app.get() - 4.9 设置
GET请求路由:app.get() - 4.10 绑定监听端口:
app.listen() - 4.11 创建路由:
app.METHOD() - 4.12 添加参数触发器:
app.param() - 4.13 返回规划路径:
app.path() - 4.14 设置
POST请求路由:app.post() - 4.15 设置
PUT请求路由:app.post() - 4.16 渲染视图:
app.render() - 4.17 返回路由单例:
app.route() - 4.18 应用设置:
app.set() - 4.19 挂载中间件:
app.use()
- 4.1 定义路由处理器:
1. 创建对象实例
app对象通过express模块导出的顶层方法express()创建:
var express = require('express');
var app = express();
app.get('/', function(req, res){
res.send('hello world');
});
app.listen(3000);
app对象中定义了一些方法,这些方法的作用有:
- 定向HTTP请求。如:app.METHOD、app.param
- 配置中间件。如:app.route
- 渲染HTML视图。如:app.render
- 设置模板引擎。如:app.engine
对象中还有一些设置属性的方法,这些设置将影响应用的形为。详见:应用设置
2. 属性
2.1 app.locals
app.locals属性是一个对象,对象中的属性是对应用内部local变量的引用。
通过app.locals设置的属性,属性值在应用的整个生命周期内都可以使用,而通过res.locals对象设置的属性只能在当前请求中使用。
app.locals.name = 'IT笔录'; app.locals.url = 'niefengjun.cn';
定义属性后,我们就可以通过local变量,在当前应用所有的渲染模中访问。通过这个属性我们可以定义一些项级的数据,并在渲染模板中使用。在局部变量中,可以通过req.app.locals访问这些属性:
req.app.locals.name; // 'IT笔录' req.app.locals.url; //'niefengjun.cn'
2.2 app.mountpath
应用做为子应用被安装时,app.mountpath包含了一个或多个路径模式。
var express = require('express');
var app = express(); // 主APP
var admin = express(); // 子APP
admin.get('/', function (req, res) {
console.log(admin.mountpath); // /admin
res.send('Admin Homepage');
});
app.use('/admin', admin); // 挂载的子应用
这类似于req对象的baseUrl属性,它不会返回req.baseUrl所匹配的路径,而是返回路径模式。
var admin = express();
admin.get('/', function (req, res) {
console.log(admin.mountpath); // [ '/adm*n', '/manager' ]
res.send('Admin Homepage');
});
var secret = express();
secret.get('/', function (req, res) {
console.log(secret.mountpath); // /secr*t
res.send('Admin Secret');
});
admin.use('/secr*t', secret); // 在'admin'子应用中,对'/secr*t'匹配结果加载'secret'路由处理器
app.use(['/adm*n', '/manager'], admin); // 在父应用中,对'/adm*n' 和 '/manager'匹配结果加载'admin'路由处理器
3. 事件
app.on('mount', callback(parent))
'mount'事件会在子应用中发生,当它被挂载到父应用时会触发'mount'事件。触发后,父应用会做回调函数参数被传调到子应用中。
var admin = express();
admin.on('mount', function (parent) {
console.log('Admin被挂载');
console.log(parent); // 对父应用的引用
});
admin.get('/', function (req, res) {
res.send('Admin Homepage');
});
app.use('/admin', admin);
4. 方法
4.1 定义路由处理器:app.all()
app.all(path, callback [, callback ...])
这个方法用于设置路由,与标准路由方法app.METHOD类似,但它会匹配所有类型的HTTP请求方法
app.all()用于映射“全局的”逻辑处理,可以匹配具体路径或任意的前缀。
如,我们可以把下面两个处理定义在路由的顶部,用户所有请求都会经过这个路径,我们可以在这个路由处理器中进行验证然后加载用户信息:
app.all('*', requireAuthentication, loadUser);
也可以分开写:
app.all('*', requireAuthentication);
app.all('*', loadUser);
请注意,这些处理一般不必做为请求的终点,在处理完成后可以通过调用next()进入下一步的处理。
我们也可以匹配部分路径,并添加“全局”处理。如,对'/api'开头路径进行用户验证:
app.all('/api/*', requireAuthentication);
4.2 定义DELETE请求路由:app.delete()
app.delete(path, callback [, callback ...])
对指定路径path定义一个针对HTTP DELETE请求的处理器。
app.delete('/', function (req, res) {
res.send('DELETE 请求主页');
});
4.3 关闭设置:app.disable()
app.disable(name)
app.disable()方法用于将指定的设置变更为false状态,其相当于调用app.set('name', false)。
app.disable('trust proxy');
app.get('trust proxy');
// => false
4.4 检查设置是否关闭:app.disabled()
app.disabled(name)
检查某项设置是否是关闭状态,如果设置为关闭状态(不可用)则返回true。
app.disabled('trust proxy');
// => true
app.enable('trust proxy');
app.disabled('trust proxy');
// => false
4.5 开启设置:app.enable()
app.enable(name)
与app.disable()方法功能相反,用于将指定的设置变更为true状态,其相当于调用app.set('name', true)。
app.enable('trust proxy');
app.get('trust proxy');
// => true
4.6 检查设置是否开启:app.enabled()
app.enabled(name)
检查某项设置是否是开启状态,如果设置为开启状态(可用)则返回true。
app.enabled('trust proxy');
// => false
app.enable('trust proxy');
app.enabled('trust proxy');
// => true
4.7 设置模块引擎:app.engine()
app.engine(ext, callback)
注册模板引擎。
默认情况下,Express会根据文件扩展名require()引用模板引擎。例如,想渲染一个"foo.jade"的文件,可以像下面这样注册,注册后设置会被缓存以提高require()的效率。
app.engine('jade', require('jade').__express);
如果不想使用.__express引擎,或要对不同扩展名使用另外的引擎。如,对".html"文件添加一个ejs引擎:
app.engine('html', require('ejs').renderFile);
4.8 获取设置值:app.get()
app.get(name)
获取指定设置的值。
app.get('title');
// => undefined
app.set('title', 'My Site');
app.get('title');
// => "My Site"
4.9 设置GET请求路由:app.get()
app.get(path, callback [, callback ...])
对指定路径path定义一个针对HTTP GET请求的路由处理器。
app.get('/', function (req, res) {
res.send('GET 请求了主页');
});
4.10 绑定监听端口:app.listen()
app.listen(port, [hostname], [backlog], [callback])
绑定并监听到指定端口和主机名的连接,这个方法等同于http.server.listen()方法。
var express = require('express');
var app = express();
app.listen(3000);
通过express()返回应用程序实际上是一个JavaScript函数,它被设计为以一个回调函数的形式传递到Node HTTP服务,以处理HTTP请求。这样就很容易在HTTP和HTTPS中使用相同的代码,因为应用的实现方式不是继承而是一个简单的回调。
var express = require('express');
var https = require('https');
var http = require('http');
var app = express();
http.createServer(app).listen(80);
https.createServer(options, app).listen(443);
app.listen()方法会返回一个http.Server对象,它的实现源码非常简单:
app.listen = function(){
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};
4.11 创建路由:app.METHOD()
app.METHOD(path, callback [, callback ...])
定义一个指定HTTP请求的路由。METHOD表示HTTP请求方式(如GET、PUT、POST等)的小写形式(如app.get()、app.put()、app.post())。
Express支持的路由请求方式有:
|
|
|
注意:在定义路由回调函数时,我们可以像定义中间件一样,定义多个回调函数。可以通过next()进入下一个回调函数,也可以通过next('route')方法跳过后面的回调函数。
app.all()是一个比较特别定义路由的方法,通过这个方法定义的路由将会在GET、PUT、POST等所有请求方式中起作用。
app.all('/secret', function (req, res, next) {
console.log('Accessing the secret section ...');
next(); // 转到下一个处理器
});
4.12 添加参数触发器:app.param()
app.param([name], callback)
将回调触发器添加到路由参数中。其中是,callback是添加的回调函数。回调函数的参数是请求对象、响应对象、下一个中间件、参数的值和参数的名称。
name:参数的名称或参数名数组callback:要添加的回调函数。其参数形式为fn(req, res, next, value),分别为请求对象、响应对象、下一个中间件、参数的值和参数的名称。
如果name是一个数组,则会在声明的每一个参数都注册回调触发器。此外,对于每个声明的参数,除了最后一个,有会有一个next回调,用于进入声明中下一个参数的回调函数。对于最后一个参数,调用下一个next将在当前正在处理的路由中调用下一个中间件。
如,对于一个/:user路径,我们对其添加一个参数触发器,然后在这个触发器中验证用户是否存在,并将获取的结果添加到req.user中:
app.param('user', function(req, res, next, id) {
// 获取用户信息,并将结果添加到request对象中
User.find(id, function(err, user) {
if (err) {
next(err);
} else if (user) {
req.user = user;
next();
} else {
next(new Error('failed to load user'));
}
});
});
所有的参数回调函数会在作何使用了参数的路由中被触发,但在同一个请求-响应周期内只被触发一次。
app.param('id', function (req, res, next, id) {
console.log('只会调用一次');
next();
});
app.get('/user/:id', function (req, res, next) {
console.log('这里会被匹配到');
next();
});
app.get('/user/:id', function (req, res) {
console.log('这里也会被匹配到');
res.end();
});
当GET请求/user/12时,依次输出如下:
只会调用一次 这里会被匹配到 这里也会被匹配到
参数触发器可以匹配一个数组,所有数组中的所有参数被匹配到时,都会触发回调函数一次。
app.param(['id', 'page'], function (req, res, next, value) {
console.log('被触发一次', value);
next();
});
app.get('/user/:id/:page', function (req, res, next) {
console.log('这里会被匹配到');
next();
});
app.get('/user/:id/:page', function (req, res) {
console.log('这里也会被匹配到');
res.end();
});
当GET请求/user/12/3时,依次输出如下:
被触发一次12 被触发一次3 这里会被匹配到 这里也会被匹配到
Express自v4.11.0以后,增加了app.param(callback);形式的参数触发器。在这种形式的参数触发器是app.param(name, callback)触发器的具体实现,它的回调函数中包含两个参数,其内部必须返回一个中间件。
var express = require('express');
var app = express();
// 自定义的 app.param()的形为
app.param(function(param, option) {
return function (req, res, next, val) {
if (val == option) {
next();
}
else {
res.sendStatus(403);
}
}
});
// 使用自定义的 app.param()
app.param('id', 1337);
// 在路由中捕获触发器
app.get('/user/:id', function (req, res) {
res.send('OK');
});
app.listen(3000, function () {
console.log('Ready');
});
4.13 返回规划路径:app.path()
app.path()
返回应用的规范路径。
var app = express()
, blog = express()
, blogAdmin = express();
app.use('/blog', blog);
blog.use('/admin', blogAdmin);
console.log(app.path()); // ''
console.log(blog.path()); // '/blog'
console.log(blogAdmin.path()); // '/blog/admin'
4.14 设置POST请求路由:app.post()
app.post(path, callback [, callback ...])
对指定路径path定义一个HTTP POST请求的路由处理器。
app.post('/', function (req, res) {
res.send('POST 请求主页');
});
4.15 设置PUT请求路由:app.post()
app.put(path, callback [, callback ...])
对指定路径path定义一个HTTP PUT请求的路由处理器。
app.put('/', function (req, res) {
res.send('PUT 请求主页');
});
4.16 渲染视图:app.render()
app.render(view, [locals], callback)
view:{String},HTML视图路径locals:{Object},可选参数。传递给HTML视图数据变量callback:{Function}。渲染结果,其形式为:fn(err, html)
通过回调函数返回一个渲染后的HTML视图,这个函数与res.render()类似,但不会将渲染结果返回给客户端。
app.render('email', function(err, html){
// ...
});
app.render('email', { name: 'Tobi' }, function(err, html){
// ...
});
4.17 返回路由单例:app.route()
app.route(path)
返回一个单一路径的实例,然后我们就可以在其中间件中处理HTTP行为。使用app.route()可以避免路由重复定义而导致错误不易定位的问题。
var app = express();
app.route('/events')
.all(function(req, res, next) {
// 首先在所有HTTP请求中运行
// 可以把它想象成一个路由中间件
})
.get(function(req, res, next) {
res.json(...);
})
.post(function(req, res, next) {
// 可以添加一个新事件
});
4.18 应用设置:app.set()
app.set(name, value)
向应用添加名称和值为name和value的设置。可添加的设置参见应用设置表
app.set('title', 'My Site');
app.get('title'); // "My Site"
应用设置表
case sensitive routing:{Boolean},默认值N/A (undefined)-设置路由大小写敏感。设置为true时,"/Foo"和"/foo"不是一个路径;设置为false时,"/Foo"和"/foo"是同一个路径env:{String},默认值process.env.NODE_ENV( NODE_ENV中设置的环境变量)-设置应用运行环境模式,应确认在生产环境的设置值为'production'etag:{Varied},默认值weak-设置ETag响应头,可选值有:{Boolean}-为true时允许使用弱ETag,这也是默认设置。{String}-为'strong'时,使用强ETag头。为'weak'时,使用弱ETag头。Function-使用自定义的ETagapp.set('etag', function (body, encoding) { return generateHash(body, encoding); // consider the function is defined });
jsonp callback name:{String},默认值callback-指定 JSONP 回调函数名json replacer:{Varied},默认值N/A (undefined)-JSON.stringify函数的'replacer'参数,'replacer' 参数json spaces:{Varied},默认值N/A (undefined)-JSON.stringify函数的'space'参数,'space' 参数query parser:{Varied},默认值'extended'-设置URL查询字符串的解析器。可选值有:false-不使用解析器'simple'-使用Node.js的querystring模块解析'extended'-使用qs模块解析function-自定义解板器,传入一个函数,返回值为包含查询字符串key-value的对象
strict routing:{Boolean},默认值N/A (undefined)-严格路由模式。设置为true时,"/foo"和"/foo/"不是同一个路径;设置为false时,"/foo"和"/foo/"是同一个路径subdomain offset:{Number},默认值2-删除子域的主机'.'分隔符数量trust proxy:{Varied},默认值false (disabled)-设置代理可信任的前缀。可设置值有:{Boolean}-设置为true时,会将IP地址理解来自于X-Forwarded-*头。设置为false时,会将IP地址理解来自于连接req.connection.remoteaddress,这也是默认值。IP addresses-一个IP地址、子网掩码或一组IP地址及其了网。预先设置的子网名为:- loopback -
127.0.0.1/8,::1/128 - linklocal -
169.254.0.0/16,fe80::/10 - uniquelocal -
10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,fc00::/7
设置IP地址时,可以像下面这样设置:
app.set('trust proxy', 'loopback') // 指定单个子网 app.set('trust proxy', 'loopback, 123.123.123.123') // 指定子网及地址 app.set('trust proxy', 'loopback, linklocal, uniquelocal') // 指定多个子网为CSV app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal']) // 以数组形式指定多个子网- loopback -
Number-信任客户端的跳转级别Function-设置自定义的信任方式。app.set('trust proxy', function (ip) { if (ip === '127.0.0.1' || ip === '123.123.123.123') return true; // 可信任的 IPs else return false; });
views:{String or Array},默认值process.cwd() + '/views'-设置应用的视图目录或数组。设置为数组时,视图的使用顺序会按其在视图中的出现顺序优先使用view cache:{Boolean},默认值:生产环境为true其它为undefined-设置是否缓存视图。view engine:{String},默认值N/A (undefined)-设置视图引擎x-powered-by:{Boolean},默认值true-设置是否允许使用X-Powered-By: Express头
4.19 挂载中间件:app.use()
app.use([path,] function [, function...])
path:{String},可选参数。挂中间件的路径function:{Function}。中间件函数,可以是多个
向指定路径path添加指定的中间件(s)。如果不指定path参数,默认为'/'
app.use('/admin', function(req, res, next) {
// GET 'http://www.example.com/admin/new'
console.log(req.originalUrl); // '/admin/new'
console.log(req.baseUrl); // '/admin'
console.log(req.path); // '/new'
next();
});
挂载中间件函数到指定路径后,中间件函数会在用户请求匹配到指定路径时自动执行中间件函数。
当向'/'路径挂载中间件后,中间件函数会在应用的所有的请求中被执行。
// 这个中间件会在应用的所有请求中执行
app.use(function (req, res, next) {
console.log('Time: %d', Date.now());
next();
});
中间件函数是按顺序执行的,所在中间件的添加顺序很重要。
// 这个中间件不允许请求通过它
app.use(function(req, res, next) {
res.send('Hello World');
});
// 用户请求永远不会到达这个路径
app.get('/', function (req, res) {
res.send('Welcome');
});
路径
路径是一个字符串,可以是一个路径、一个路径模式匹配、一个正则表达式、或一个数组。下面是一些中间件的例子:
路径如,匹配'/abcd'路径:
app.use('/abcd', function (req, res, next) { next(); });路径模式匹配如,匹配'/abcd'或'/abd'路径:
app.use('/abc?d', function (req, res, next) { next(); });如,匹配'/abcd'、'/abbcd'或'/abbbbbcd'等路径:
app.use('/ab+cd', function (req, res, next) { next(); });如,匹配'/abcd'、'/abxcd'、'/abFOOcd'或'/abbArcd'等路径:
app.use('/ab\*cd', function (req, res, next) { next(); });正则表达式如,匹配'/abc'和'/xyz'路径:
app.use(/\/abc|\/xyz/, function (req, res, next) { next(); });数组如,匹配'/abcd'、'/xyza'、'/lmn'和'/pqr'路径:
app.use(['/abcd', '/xyza', /\/lmn|\/pqr/], function (req, res, next) { next(); });
中间件
中间件函数是一个函数。可以是一个函数、多个函数、函数数组或是几都的混合。
router和app都实现在了中间件接口,所以你可以它们二者之间使用中间件。
单个中间件在应用中使用单个中间件:
app.use(function (req, res, next) { next(); });将路由中作为中间件使用:
var router = express.Router(); router.get('/', function (req, res, next) { next(); }); app.use(router);var subApp = express(); subApp.get('/', function (req, res, next) { next(); }); app.use(subApp);
多个中间件可以在一个路径中定义多个中间件:
var r1 = express.Router(); r1.get('/', function (req, res, next) { next(); }); var r2 = express.Router(); r2.get('/', function (req, res, next) { next(); }); app.use(r1, r2);数组可以将多个中间件逻辑放到一个数组中使用:
var r1 = express.Router(); r1.get('/', function (req, res, next) { next(); }); var r2 = express.Router(); r2.get('/', function (req, res, next) { next(); }); app.use('/', [r1, r2]);综合使用可以将多种方式一起使用:
function mw1(req, res, next) { next(); } function mw2(req, res, next) { next(); } var r1 = express.Router(); r1.get('/', function (req, res, next) { next(); }); var r2 = express.Router(); r2.get('/', function (req, res, next) { next(); }); var subApp = express(); subApp.get('/', function (req, res, next) { next(); }); app.use(mw1, [mw2, r1, r2], subApp);
