# Express 中间件

  • Express 中间件,本质是一个处理函数
const express = require('experss')
const app = express()
app.get('/', (req, res, next) => {
  next()
})
app.listen(8001)
  • 中间件函数的形参中,必须包含 next 参数。而路由处理函数中只包含 reqres

# 全局生效的中间件

  • 客户端发起的任何请求,到达服务器之后,都会触发的中间件,叫做全局生效的中间件
  • 通过调用 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()
}
//mv1 中间件只在当前路由生效 也就是局部生效的中间件
app.get('/', mw1, (req, res) => {
  res.send('Home')
})
//mv1 中间件不会印象下面路由
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+ 版本中可用)
// 配置解析 application/json 格式数据的内置中间件
app.use(express.json())
// 配置解析 application/x-www-form-urlencoded
app.use(express.urlencoded({extended: false}))

# express.json

const express = require('express')
const app = express()
// 注意 处理错误级别中间件 其他中间件必须在路由之前进行配置
// 通过 express.json () 这个中间件,解析表单中的 JSON 格式数据
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()
// 通过 express.urlencoded () 这个中间件,解析表单中的 url-encoded 格式数据
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()
// 导入解析表单数据的中间件 body-parser 
const parser = require('body-parser')
// 使用 app.use 注册中间件
app.use(parser.urlencoded({ extended: false }))
app.post('/user', (req, res) => {
  // 如果没有配置任何解析表单数据的中间件 则 req.body 默认是 undefined
  console.log(req.body)
  res.send('ok')
})
app.listen(8001)

# 自定义中间件

  • 自己手动模拟一个类似于 express.urlencoded 这样的中间件,来解析 POST 提交到服务器的表单数据。
  • 实现步骤:
    • 定义中间件
    • 监听 req 的 data 事件
    • 监听 req 的 end 事件
    • 使用 querystring 模块解析请求体数据
    • 将解析出来的数据对象挂载为 req.body
    • 将自定义中间件封装为模块

# 封装中间件函数

  • 在中间件中,需要监听 req 对象的 data 事件,来获取客户端发送到服务器的数据。

  • 如果数据量比较大,无法一次性发送完毕,则客户端会把数据切割后,分批发送到服务器。所以 data 事件可能会触发多次,每一次触发 data 事件时,获取到数据只是完整数据的一部分,需要手动对接收到的数据进行拼接。

  • 当请求体数据接收完毕之后,会自动触发 reqend 事件。

  • customBodyParser.js

// 1. 导入 Node 内置的 querystring 模块
const querystring = require('querystring')
module.exports = (req, res, next) => {
  let str = ''
  // 2. 监听 req data 事件 (客户端发送过来的新的请求体数据)
  req.on('data', chunk => {
    str += chunk
  })
  // 3. 监听 req end 事件 (请求体发送完毕后自动触发)
  req.on('end', () => {
    // TODO: 把字符串格式的请求体数据 解析为对象格式
    req.body = querystring.parse(str)
    next() // 不要忘记 next 哦
  })
}

# 使用封装的函数

  • index.js
// 1. 导入 express 模块
const express = require('express')
// 2. 导入 封装的 自定义 中间件模块
const customBodyParser = require('./customBodyParser')
// 3. 创建 express 服务器实例
const app = express()
// 4. 使用 app.use 定义全局生效用来解析数据的中间件
app.use(customBodyParser)
app.post('/user', (req, res) => {
  res.send(req.body)
})
app.listen(8001)

# Express 写接口

# GET 接口

  • router.js
// TODO GET 接口
const express = require('express')
const router = express.Router()
// 挂载对应的路由
router.get('/get', (req, res) => {
  // 通过 req.query 获取客户端查询字符串 发送到服务器数据
  const query = req.query
  // 调用 res.send 方法 向客户端响应处理的结果
  res.send({
    status: 200,       // 状态码
    data: query,       // 相应给客户端的数据
    msg: 'GET请求成功'  // 状态描述
  })
})
module.exports = router
  • index.js
const express = require('express')
const router = require('./router')
// 创建 express 实例
const app = express()
// 注册路由模块到 app 上
app.use('/api', router)
// 启动服务器
app.listen(8001)

# POST 接口

  • router.js
// TODO POST 接口
const express = require('express')
const router = express.Router()
// 挂载对应的路由
router.post('/post', (req, res) => {
  // 通过 req.query 获取客户端查询字符串 发送到服务器数据
  const body = req.body
  // 调用 res.send 方法 向客户端响应处理的结果
  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')
// 创建 express 实例
const app = express()
// 配置解析表单数据中间件
app.use(express.urlencoded({ extended: false }))
// 注册路由模块到 app 上
app.use('/api', router)
// 启动服务器
app.listen(8001)
Update on Views times

Give me a cup of [coffee]~( ̄▽ ̄)~*

Nico Niconi WeChat Pay

WeChat Pay

Nico Niconi Alipay

Alipay