一、中间件引入
实现加入日志模块功能:
1. 我们能想到的方案:
将日志输出代码封装到函数中,然后需要日志输出的地方调用这个函数即可。
app.js文件:
const express = require('express')const app = express()const myLogger = (req) => {console.log(req.method, req.url, Date.now())}app.get('/', (req, res) => {myLogger(req)res.send('get /')
})app.get('/about', (req, res) => {myLogger(req)res.send('get /about')
})app.get('/login', (req, res) => {myLogger(req)res.send('get /login')
})// app.get('/', (req, res) => {
// console.log(req.method, req.url, Date.now())
// res.send('get /')
// })// app.get('/about', (req, res) => {
// console.log(req.method, req.url, Date.now())
// res.send('get /about')
// })// app.get('/login', (req, res) => {
// console.log(req.method, req.url, Date.now())
// res.send('get /login')
// })app.listen(3000, () => {console.log('Server running at http://localhost:3000/')
})
2. 使用中间件
二、中间件的概念
在我理解Express 中间件和AOP面向切面编程就是一个意思,就是都需要经过经过的一些步骤,不去修改自己的代码,以此来扩展或者处理一些功能。
什么是AOP?中文意思是面向切面编程,听起来感觉很模糊。先举个生产的例子。
最后在流水线中的空隙插上两个工人去处理,形成采摘-分类-清洗-包装
-贴标签的新流程,而且工人可以随时撤回。
AOP(Aspect Oriented Programming)面向切面编程:
- 将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
- 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率和可维护性。
总结:就是在现有代码程序中,在程序生命周期或者横向流程中加入/减去一个或多个功能,不影响原有功能。
三、Express中的中间件
在Express中,中间件就是一个可以访问请求对象、响应对象和调用next方法的一个函数。
在中间件函数中可以执行以下任何任务:
- 执行任何代码
- 修改request 或者response响应对象
- 结束请求响应周期
- 调用下一个中间件
注意:如果当前的中间件功能没有结束请求-响应周期,则必须调用next()将控制权传递给下一个中间件功能。否则,该请求将被挂起。
四、Express中的中间件分类
在Express中应用程序可以使用以下类型的中间件:
- 应用程序级别中间件
此示例显示了一个中间件子堆栈,该子堆栈处理对/user/:id路径的GET请求。
- next() 不带参数
表示继续跳转执行下一个middle或者route函数。 - next(‘route’)
表示丢弃当前route的剩余callback函数,注意只在由app.METHOD()/route.METHOD()中定义的middleware函数中生效。 - next(! ‘route’)
对于任何非’route’参数(不管是一个简单数字或者还是一个字符串)都被认为是一个err,跳转到错误处理函数。
中间件也可以在数组中声明为可重用。此示例显示了一个带有中间件子堆栈的数组,该子堆栈处理对/user/:d路径的GET请求
- 路由级别中间件
路由器级中间件与应用程序级中间件的工作方式相同,只不过它绑定到实例express.Router()
var router=express.Router()
使用router.use()和router.METHOD()函数加载路由器级中间件.
以下示例代码通过使用路由器级中间件来复制上面显示的用于应用程序级中间件的中间件系统:
- 错误处理中间件
以与其他中间件函数相同的方式定义错误处理中间件函数,除了使用四个参数而不是三个参数(特别是使用签名(err,req,res,next))之外:
错误处理中间件始终带有四个参数。你必须提供四个参数以将其标识为错误处理中间件函数。即使不需要使用该next对象,也必须指定它以维护签名。否则,该next 对象将被解释为常规中间件,并且将无法处理错误。
如果将任何内容传递给该next()函数(字符串除外’route’),Express都会将当前请求视为错误,并且将跳过所有剩余的非错误处理路由和中间件函数。
中间件处理404:
-
内置中间件
Express 具有以下内置中间件函数:
-
第三方中间件
早期的Express内置了很多中间件.后来Express在4.x之后移除了这些内置中间件,官方把这些功能性中间件以包的形式单独提供出来.这样做的目的是
为了保持Express本身极简灵活的特性,开发人员可以根据自己的需要去灵
活的使用.
有关Express常用的第三方中间件功能的部分列表,请参阅:
https://www.expressjs.com.cn/resources/middleware.html
第三方中间件morgan的使用:
morgan用来输出日志信息
- npm i morgan
var morgan = require('morgan')
// app.use(morgan('tiny'))
app.use(morgan(':method :url :status :res[content-length] - :response-time ms'))