这是我参与8月更文挑战的第17天,活动详情查看:8月更文挑战
Express中间件
一、认识Express中间件
Express最大的特点就是它的中间件,一个Express应用就是由许许多多的中间件来完成的。每一个路由就是一个中间件;Express中间件跟AOP面向切面编程是一个意思。
AOP面向切面编程:将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码;利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时也提高了开发效率和可维护性。也就是在现有代码程序中,在程序生命周期或者横向流程中增删一个或多个功能时而不影响其它功能的实现。
在Express中,中间件就是一个可以访问请求对象、响应对象和调用next(调用下一个中间件)方法的一个函数;在中间件函数中可以执行以下任务:
- 执行任何代码
- 修改request或者response响应对象
- 结束请求响应周期
- 调用下一个中间件
app.use((req, res, next) => {
req.foo = 'bar';
res.handle=()=>{...};
next();
})
中间件的先后顺序是很重要的,且中间件所获取到的request和response都是同一个的,上一个中间件给request或response中加的值,在下一个中间件中是可以获取到的,但如果把它们先后顺序交换的话返回的就是undefined;
二、Express中间件分类
- 应用程序级别中间件
- 路由级别中间件
- 错误处理中间件
- 内置中间件
- 第三方中间件
1. 应用程序级中间件
-
不做任何限定的中间件,任何请求都会经过它
app.use(function (req, res, next) { console.log('Time', Date.now()); next(); }) -
限定请求路径,只有请求路径符合规则才能匹配到这个中间件;
app.get('/user/:id', (req, res) => { console.log('Request Type', req.method); // GET next(); }) -
多个处理函数,可以在一个中间件中配置多个处理函数;这里面的next是往下一个函数找,找到最后一个处理函数的时候再跳到下一个中间件;
-
也可以给同一个路径定义多个中间件,可以用
next()跳到下一个中间件,但是对于处理同一个路径的中间件,不能发送多个响应;app.get('/user/:id', (req, res, next) => { if (req.params.id === '0') next('route'); else next(); }, function (req, res, next) { res.send('normal'); }) app.get('/user/:id', function (req, res, next) { res.send('special'); }
上面这段代码,如果满足if判断语句的条件,响应的就是res.send('special'),否则,就是res.send('special');
如果要从路由器中间件堆栈中跳过其余中间件功能,调用next('route')将控制权传递给下一条路由;注意:next('route')仅在使用app.METHOD()或router.METHOD()函数加载的中间件函数有效(app.use不行);
- 中间件也可以再数组中声明为可重用,该数组可以放在
app.METHOD()的第二个参数中
2. 路由器级中间件
路由器级中间件与应用程序级中间件的工作方式相同,只不过它绑定到的实例express.Router()
var router = express.Router();
使用router.use()和router.METHOD()函数加载路由器级中间件;可以在文件夹中创建一个router.js来创建路由:
-
引入模块,创建路由实例;路由实例相当于一个比较小的Express实例;
const express = require('express'); const router = express.router(); -
配置路由并导出
router.get('/foo', (req, res) => { res.send('get/foo') }) module.exports = router; -
将路由挂载到Express实例应用中,去到
app.js文件中把这个router.js文件引入,引入后挂载路由app.use(router)即可。app.use的第一个参数可以传限定访问前缀,比如app.use('/aaa', router),就要通过/aaa/foo才可以匹配到在router中配置的路由;
3. 错误处理中间件
处理错误中间件始终带有4个参数,必须提供4个参数以将其标识为错误处理中间件函数。即使不需要使用某个参数,也必须写上这4个参数;应该在所有中间件之后挂载错误处理中间件
app.use((err, req, res, next) => {
console.log(err);
res.status(500).json({
error: err.message
})
})
将任何内容传递给next()函数,Express都会将当前请求视为错误,并且跳过所有剩余无错误处理路由和中间件函数;因此在app.METHOD()中的catch(err)中要让它catch(err);当又错误的时候,调用next(err),就会跳过其它中间件,跳到错误处理路由;
4. 处理404中间件
放到所有的路由之后进行配置;请求进来从上到下依次匹配,这个处理404中间件是在所有路由都没匹配到之后所返回的,跟错误处理中间件是不一样的;
app.use((req, res, next) => {
res.status(404).send('404 Not Found');
})
5. 内置中间件
express.json:解析Content-Type为application/json格式的请求体express.urlencoded():解析Content-Type为application/x-www-form-urlencoded格式的请求体express.raw():解析Content-Type为application/octet-stream格式的请求体express.text():解析Content-Type为text.plain格式的请求体express.static():托管静态资源文件
6. 第三方中间件
使用步骤:
-
下载第三方中间件的包,比如
npm install morgan; -
配置中间件(看文档操作
const morgan = require('morgan'); app.use(morgan(':method :status :res[content-length] :response-time ms'));