Express 的中间件
Express 的中间件,本质上就是一个 function 处理函数. Express中间件的格式如下:
需要注意的是:中间件有三个参数。在中间件的形参列表中。 必须包含next参数;它既是参数也是函数。 其中路由处理函数中有req和res。 有的小伙伴可能会问呢? 我怎么知道是一个函数还是一个中间件。他们实在是长得太像了。 其实:我们可以通过第三个参数来判断是不是中间件。 next函数的作用 next 函数是实现多个中间件连续调用的关键, 它表示把流转关系转交给下一个中间件或路由。 我们可以理解为前端路由中路由守卫中的next。
中间件的调用流程
当一个请求到达 Express的服务器之后, 可以连续调用多个中间件,从而对这次请求进行[预处理]。
定义一个简单的中间件
// 常量 mw 所指向的,就是一个中间件函数 const mw = function (req, res, next) { console.log("我是一个中间件') // 注意: 在当前中间件的业务处理完毕后,必须调用 next() 函数 // 表示把流转关系转交给下一个中间件或路由next() }
注册一个全局生效的中间件
客户端发起的任何请求,到达服务器之后,都会触发的中间件,叫做全局生效的中间件。 expres中通过调用 app.use(中间件函数),即可定义一个全局生效的中间件,代码如下: //常量 mw 所指向的,就是一个中间件函数 const mw = function (req, res, next) { console.log('这是一个最简单的中间件函数') next() } // 全局生效的中间件 app.use(mw)
调用请求接口,全局中间件被触发
const express = require("express"); const app = express(); //常量 mw 所指向的,就是一个中间件函数 const mw = function (req, res, next) { console.log('这是一个最简单的中间件函数,我将会被触发') next() } // 全局生效的中间件 app.use(mw) // 监听客户端的get请求 app.get('/user', (req, res) => { res.send({name:'张三',age:22, type:'admin'}) }) app.listen(3000, () => { console.log('express serve Started successfully') })
在浏览器中输入 http://127.0.0.1:3000/user 会触发中间件
需要注意中间件的一个顺序问题
如果我们把中间件放在路由的后面。 这样中间件会失效的。 因为代码从上往下执行。路由都执行完了。就不关中间件什么事情了。 像下面这一种:把中间件放在路由后面。中间件将不会被执行 app.get('/user', (req, res) => { res.send({name:'张三',age:22, type:'admin'}) }) const mw = function (req, res, next) { console.log('这是一个最简单的中间件函数,我将会被触发') next() } app.use(mw)
定义多个全局中间件
我么可以使用 app.use()连续定义多个全局中间件。 就像之前定义多个静态服务一样。 客户端请求到达服务器之后,会按照中间件定义的先后顺序依次进行调用。 代码如下:
//常量 mw 所指向的,就是一个中间件函数 const mw1 = function (req, res, next) { console.log('我是第1个中间件') next() } const mw2 = function (req, res, next) { console.log('我是第2个中间件') next() } // 全局生效的中间件1 app.use(mw1) // 全局生效的中间件2 app.use(mw2)
局部生效的中间件
有的小伙伴可能会问,上面是全局中间件。 有没有局部中间件呢? 有的! 局部中间件是这样定义的: 不使用app.use()定义的中间件,叫做局部中间件。 也就是说:有app.use()的是全局中间件。没有app.use()定义的是局部中间件
const express = require("express"); const app = express(); //常量 mw1 所指向的,就是一个中间件函数 const mw1 = function (req, res, next) { console.log('我是局部生效的中间件') next() } // 监听客户端的get请求,局部中间件不会影响这个user请求 app.get('/user', (req, res) => { res.send({name:'张三',age:22, type:'admin'}) }) // 当请求list的之后,这个中间件只会在list中生效 app.get('/list',mw1, (req, res) => { res.send([{name:'张三',age:22, type:'admin'}]) }) app.listen(3000, () => { console.log('express serve Started successfully') })
04png
定义多个局部中间件
有些时候,我们针对某一个请求。 可能需要使用多个中间件。这个时候多个局部中间件就出场了。 下面是多个局部中间件的两种方式: //定义了中间件mw1,mv2。使用逗号隔开:多个中间件 app.get('/list',mw1,mv2, (req, res) => { res.send('我是list请求') }) //定义了中间件mw1,mv2。把多个中间件放在一个数组中 app.get('/user',[mw1,mv2], (req, res) => { res.send('我是list请求') })
express 中间件的分类
Express 官方把常见的中间件用法,分成了 5 大类。 1.应用级别的中间件 2.路由级别的中间件 3.错误级别的中间件 4.Express 内置的中间件 5.第三方的中间件
应用级别的中间件
通过 app.use()或 app.get()或 app.post(), 绑定到 app 实例上的中间件,叫做应用级别的中间. 我们上面写的代码,就算是应用级别的中间件
路由级别的中间件
绑定到 express.Router()实例上的中间件,叫做路由级别的中间件。 它的用法和应用级别中间件没有任何区别。 只不过,应用级别中间件是绑定到 app 实例上. 路由级别中间件绑定到 router 实例上
错误级别的中间件
错误级别中间件的作用:专门用来捕获整个项目中发生的异常错误, 从而防止项目异常崩溃的问题。 下面我们抛出一个异常。
const express = require("express"); const app = express(); // 当请求 file 之后,虽然项目发生了错误,但是不会让项目崩掉 app.get('/file', (req, res) => { res.send({info:'发生错误'}) throw new Error('服务器咋开小差') }) //这中间件在路由后面。 app.use((err,req,res,next) => { console.log('发生了错误:', err) res.send('error:', err.message) }) app.listen(3000, () => { console.log('express serve Started successfully') })
关于错误级别的中间件的特殊点
有的小伙伴看了上面的代码。发现很奇怪。 不是说的: 把中间件放在路由后面。中间件将不会被执行。 咋个还执行了呢? 因为:错误级别的中间件比较特殊。 必须注册在所有的路由之后。
Express 内置的中间件
自Express 4.16.0 版本开始,Express 内置了3 个常用的中间件. 1==> express.static 托管静态资源的内置中间件. 例如: HTML 文件、图片、CSS 样式等(无兼容性) 2==> express.json 解析JSON 格式的请求体数据 (有兼容性,仅在 4.16.0+ 版本中可用) 3==> express.urlencoded 解析 URL-encoded 格式的请求体数据(有兼容性,仅在 4.16.0+ 版本中可用)
// 配置解析 application/json 格式数据的内置中间件 app.use(express.json( )) // 配置解析 application/x-w-form-urlencoded 格式数据的内置中间件 app.use(express.urlencoded({ extended: false }))