# Express 中间件
| const express = require('experss') |
| const app = express() |
| |
| app.get('/', (req, res, next) => { |
| next() |
| }) |
| |
| app.listen(8001) |
- 中间件函数的形参中,必须包含
next
参数。而路由处理函数中只包含 req
和 res
# 全局生效的中间件
- 客户端发起的任何请求,到达服务器之后,都会触发的中间件,叫做全局生效的中间件
- 通过调用
app.use(中间件函数)
,即可定义一个全局生效的中间件,如下也可以同时定义多个中间件,客户端请求到达服务器之后,会按照中间件定义顺序先后执行
| const mw1 = function (req, res, next) { |
| console.log('第一个中间件'); |
| |
| next() |
| } |
| |
| const mw2 = function (req, res, next) { |
| console.log('第二个中间件'); |
| |
| next() |
| } |
| |
| app.use(mw1) |
| app.use(mw2) |
# 局部生效的中间件
- 不使用
app.use()
定义的中间件,称作局部生效的中间件,如下
| |
| const mw1 = (req, res, next) => { |
| console.log('中间件调用'); |
| next() |
| } |
| |
| |
| app.get('/', mw1, (req, res) => { |
| res.send('Home') |
| }) |
| |
| |
| app.get('/user', (req, res) => { |
| res.send('User') |
| }) |
| const express = require('express') |
| const app = express() |
| |
| const mw1 = (req, res, next) => { |
| console.log('这是第一个中间件'); |
| next() |
| } |
| |
| const mw2 = (req, res, next) => { |
| console.log('这是第二个中间件'); |
| next() |
| } |
| |
| app.get('/', mw1, mw2, (req, res) => { |
| res.send('Home') |
| }) |
| |
| app.get('/user', (req, res) => { |
| res.send('User') |
| }) |
| |
| app.listen(8001, () => { |
| console.log('http://127.0.0.1:8001'); |
| }) |
- 关于中间件的 5 个使用注意事项
- 一定要在
路由之前
注册中间件
- 客户端发送过来的请求,
可以连续调用多个
中间件进行处理
- 执行完中间件的业务代码之后 z
不要忘记调用 next() 函数
- 为了
防止代码逻辑混乱
,调用 next () 函数后不要再写额外的代码
- 连续调用多个中间件时,多个中间件之间,
共享
s req 和 res 对象
# Express 中间件的分类
# 应用级别的中间件
- 通过 app.use () 或 app.get () 或 app.post () ,绑定到 app 实例上的中间件,叫做应用级别的中间件,如下:
| |
| app.use((req, res, next) => next()) |
| |
| |
| app.get('/', mw, (req, res) => res.send('Hello World')) |
# 路由级别的中间件
- 绑定到 express.Router () 实例上的中间件,叫做路由级别的中间件。它的用法和应用级别中间件没有任何区别。只不过,应用级别中间件是绑定到 app 实例上,路由级别中间件绑定到 router 实例上,如下:
| const app = express() |
| const router = express.Router() |
| |
| |
| router.use((req, res, next) => next()) |
| |
| app.use('/', router) |
# 错误级别的中间件
- 错误级别中间件的 function 处理函数中,必须有 4 个形参,形参顺序从前到后,分别是 (err, req, res, next)。
| app.get('/', (req, res) => { |
| throw new Error('服务器内部发生了错误!') |
| res.send('Hello World') |
| }) |
| |
| app.use((err, req, res, next) => { |
| console.log(`发生了错误: ${}`) |
| res.send('Error~' + err.message) |
| }) |
# Express 内置的中间件
- 自 Express 4.16.0 版本开始,Express 内置了 3 个常用的中间件,极大的提高了 Express 项目的开发效率和体验:
- express.static 快速托管静态资源的内置中间件,例如: HTML 文件、图片、CSS 样式等(无兼容性)
- express.json 解析 JSON 格式的请求体数据(有兼容性,仅在 4.16.0+ 版本中可用)
- express.urlencoded 解析 URL-encoded 格式的请求体数据(有兼容性,仅在 4.16.0+ 版本中可用)
| |
| app.use(express.json()) |
| |
| |
| app.use(express.urlencoded({extended: false})) |
# express.json
| const express = require('express') |
| |
| const app = express() |
| |
| |
| |
| app.use(express.json()) |
| |
| app.post('/user', (req, res) => { |
| console.log(req.body) |
| res.send('ok') |
| }) |
| |
| app.listen(8001) |
#### express.urlencoded
| const express = require('express') |
| |
| const app = express() |
| |
| |
| app.use(express.urlencoded({ extended: true })) |
| |
| app.post('/book', (req, res) => { |
| console.log(req.body) |
| res.send(req.body) |
| }) |
| |
| app.listen(8001) |
# 第三方的中间件
-
非 Express 官方内置的,而是由第三方开发出来的中间件,叫做第三方中间件。在项目中,大家可以按需下载并配置第三方中间件,从而提高项目的开发效率。
-
例如:在 express@4.16.0 之前的版本中,经常使用 body-parser 这个第三方中间件,来解析请求体数据。使用步骤如下:
-
运行 npm install body-parser 安装中间件
-
使用 require 导入中间件
-
调用 app.use () 注册并使用中间件
-
注意 Express 内置的 express.urlencoded 中间件,就是基于 body-parser 这个第三方中间件进一步封装出来的。
| const express = require('express') |
| |
| const app = express() |
| |
| |
| const parser = require('body-parser') |
| |
| |
| app.use(parser.urlencoded({ extended: false })) |
| |
| app.post('/user', (req, res) => { |
| |
| console.log(req.body) |
| res.send('ok') |
| }) |
| |
| app.listen(8001) |
# 自定义中间件
- 自己手动模拟一个类似于 express.urlencoded 这样的中间件,来解析 POST 提交到服务器的表单数据。
- 实现步骤:
- 定义中间件
- 监听 req 的 data 事件
- 监听 req 的 end 事件
- 使用 querystring 模块解析请求体数据
- 将解析出来的数据对象挂载为 req.body
- 将自定义中间件封装为模块
# 封装中间件函数
-
在中间件中,需要监听 req 对象的 data 事件,来获取客户端发送到服务器的数据。
-
如果数据量比较大,无法一次性发送完毕,则客户端会把数据切割后,分批发送到服务器。所以 data 事件可能会触发多次,每一次触发 data 事件时,获取到数据只是完整数据的一部分,需要手动对接收到的数据进行拼接。
-
当请求体数据接收完毕之后,会自动触发 req
的 end
事件。
-
customBodyParser.js
| |
| const querystring = require('querystring') |
| |
| module.exports = (req, res, next) => { |
| let str = '' |
| |
| |
| req.on('data', chunk => { |
| str += chunk |
| }) |
| |
| |
| req.on('end', () => { |
| |
| req.body = querystring.parse(str) |
| next() |
| }) |
| } |
# 使用封装的函数
| |
| const express = require('express') |
| |
| |
| const customBodyParser = require('./customBodyParser') |
| |
| |
| const app = express() |
| |
| |
| app.use(customBodyParser) |
| |
| app.post('/user', (req, res) => { |
| res.send(req.body) |
| }) |
| |
| app.listen(8001) |
# Express 写接口
# GET 接口
| |
| const express = require('express') |
| |
| const router = express.Router() |
| |
| |
| router.get('/get', (req, res) => { |
| |
| const query = req.query |
| |
| |
| res.send({ |
| status: 200, |
| data: query, |
| msg: 'GET请求成功' |
| }) |
| }) |
| |
| module.exports = router |
| const express = require('express') |
| const router = require('./router') |
| |
| |
| const app = express() |
| |
| |
| app.use('/api', router) |
| |
| |
| app.listen(8001) |
# POST 接口
| |
| const express = require('express') |
| |
| const router = express.Router() |
| |
| |
| router.post('/post', (req, res) => { |
| |
| const body = req.body |
| |
| |
| res.send({ |
| status: 200, |
| data: body, |
| msg: 'POST请求成功' |
| }) |
| }) |
| |
| module.exports = router |
index.js
- 注意 如果要获取 URL-encoded 格式的请求体数据,必须配置中间件
app.use(express.urlencoded({ extended: false }))
| const express = require('express') |
| const router = require('./router') |
| |
| |
| const app = express() |
| |
| |
| app.use(express.urlencoded({ extended: false })) |
| |
| |
| app.use('/api', router) |
| |
| |
| app.listen(8001) |