router
路由器对象是一个独立的中间件和路由实例。你可以把它想象成一个“迷你应用程序”,只能够执行中间件和路由功能。每个Express应用都有一个内置的应用路由器。
1. Router
对象
路由器的行为表现本身就像一个中间件,所以你可以使用它做为参数传递给app.use()或做为参数传递给另一个器由器的use()方法。
Exress顶层对象有个Router()
方法,这是一个构造函数,可以创建一个新的router
(路由器对象实例)。
var express = require('express'); var router = express.Router();
router
对象创建后,就可以像应用一样添加中间件和HTTP方法(get、put、post等)了。
// 所有请求都会传递给该路由 router.use(function(req, res, next) { // 业务逻辑,类似一个中间件 next(); }); // 捕获 /events 路径的 GET 请求 router.get('/events', function(req, res, next) { // .. });
你可以使用use()
方法将路由器添加到一个特殊的根网址,这样你就可以把你的路由分为不同的文件甚至小型应用。
// 只有请求 /calendar/* 才会被发送到 "router"处理 app.use('/calendar', router);
2. 方法
2.1 创建路由:router.all()
router.all(path, [callback, ...] callback)
类似app.all()方法,将匹配所有HTTP方法。
这个方法可以用映射“全局的”逻辑处理,可以匹配具体路径或任意的前缀。
我们可以把all
处理定义的路由放在其它路由的顶部,用户所有请求都会经过这个路径,我们可以在这个路由处理器中进行用户验证和0加载用户信息信息等处理。
router.all('*', requireAuthentication, loadUser);
也可以分开写:
router.all('*', requireAuthentication) router.all('*', loadUser);
我们也可以匹配部分路径,并添加“全局”处理。如,对'/api'开头路径进行用户验证:
router.all('/api/*', requireAuthentication);
2.2 创建指定HTTP方法的路由:router.METHOD()
router.METHOD(path, [callback, ...] callback)
router.METHOD()
是Express提供的路由功能,METHOD
是HTTP方法如:GET、PUT、POST等的小写形式,对应的路由方法分别为router.get()
、router.put()
、router.post()
等,Express支持的路由方法有:Express支持的路由方式。
注意:在定义路由回调函数时,我们可以像定义中间件一样,定义多个回调函数。可以通过next()
进入下一个回调函数,也可以通过next('route')
方法跳过后面的回调函数。
router.get('/', function(req, res){ res.send('hello world'); });
router.METHOD()
同样支持正则表达式:
router.get(/^\/commits\/(\w+)(?:\.\.(\w+))?$/, function(req, res){ var from = req.params[0]; var to = req.params[1] || 'HEAD'; res.send('commit range ' + from + '..' + to); });
2.3 定义参数触发器:router.param()
router.param(name, callback)
添加路由参数的参数触发器,name
表示路由参数,callback
表示触发器回调函数,其形式为:
与app.param()一样,自Expressv4.11.0
以后,增加了router.param(name, callback)
形式的触发器。
var express = require('express'); var app = express(); var router = express.Router(); // 自定义 router.param() 处理器 router.param(function(param, option) { return function (req, res, next, val) { if (val == option) { next(); } else { res.sendStatus(403); } } }); // 使用自定义的 router.param() router.param('id', 1337); // 捕获路由触发器 router.get('/user/:id', function (req, res) { res.send('OK'); }); app.use(router); app.listen(3000, function () { console.log('Ready'); });
2.4 返回路由单例:router.route()
router.route(path)
返回一个单一路径的实例,然后我们就可以在其中间件中处理HTTP行为。使用app.route()
可以避免路由重复定义而导致错误不易定位的问题。
var router = express.Router(); router.param('user_id', function(req, res, next, id) { // sample user, would actually fetch from DB, etc... req.user = { id: id, name: 'TJ' }; next(); }); router.route('/users/:user_id') .all(function(req, res, next) { // runs for all HTTP verbs first // think of it as route specific middleware! next(); }) .get(function(req, res, next) { res.json(req.user); }) .put(function(req, res, next) { // just an example of maybe updating the user req.user.name = req.params.name; // save user ... etc res.json(req.user); }) .post(function(req, res, next) { next(new Error('not implemented')); }) .delete(function(req, res, next) { next(new Error('not implemented')); });
2.5 挂载中间件:router.use()
router.use([path], [function, ...] function)
path
:{String},可选参数。挂中间件的路径function
:{Function}。中间件函数,可以是多个
向指定路径path
添加指定的中间件(s)。如果不指定path
参数,默认为'/'
。
这个方法与app.use()方法类似。
中间件就像一个请求管道(pipe),会从请求的第一个中间件开始,依次向下传递到每一个可匹配的路径。
var express = require('express'); var app = express(); var router = express.Router(); // 一个简单的日志打印中间件,所有的请求首先会经过这个中间件 router.use(function(req, res, next) { console.log('%s %s %s', req.method, req.url, req.path); next(); }); // 这个中间件只会匹配到'/bar'开头的路径 router.use('/bar', function(req, res, next) { // ... /bar 下的一些逻辑处理 ... next(); }); // 总会被调用 router.use(function(req, res, next) { res.send('Hello World'); }); app.use('/foo', router); app.listen(3000);
“挂载”的中间件和路径功能是分离的,路径对于中间件来说是不可见的。这个方法的主要作用时,挂载中间件而不需要修改代码,也不需要考虑“前缀”是什么。
中间件的安装(挂载)顺序非常重要,这决定了中间件的调用顺序。
var logger = require('morgan'); router.use(logger()); router.use(express.static(__dirname + '/public')); router.use(function(req, res){ res.send('Hello'); });
注意:虽然中间件的功能是通过路由处理器添加的,它们运行时确是关联到了添加它的路径上(非路由处理器)。这样,中间件虽然这个路由器添回,确可能运行在另一个路由器匹配到的路径上。
var authRouter = express.Router(); var openRouter = express.Router(); authRouter.use(require('./authenticate').basic(usersdb)); authRouter.get('/:user_id/edit', function(req, res, next) { // ... Edit user UI ... }); openRouter.get('/', function(req, res, next) { // ... List users ... }) openRouter.get('/:user_id', function(req, res, next) { // ... View user ... }) app.use('/users', authRouter); app.use('/users', openRouter);