• Node.js 知识整理之第三篇(Express中间件)


    简介

    • 本篇博客主要记录了express中间件

    Express 中间件

    中间件格式

    • 中间件函数的形参数列表中,必须有 next参数,而路由处理参数中只包含req 和 res
    • 书写格式如下:
        const express = require('express')
        const app = express()
        app.get('/',(req,res,next)=>{
           next()
        })
        app.listen('8088',()=>{
            console.log('express server running at http://127.0.0.1:8088')
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    next 函数的作用

    • next函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或者路由
    • avatar

    定义中间件

        const  express = require('express')
        const  app = express()
        //定义一个中间件
        const c1 = function (req,res,next){
            console.log('这是一个中间件函数')
            // 把流转关系,转交给下一个中间件或路由
            next()
        }
        app.listen('8088',()=>{
            console.log('express server running is http://127.0.0.1:8088')
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    全局生效的中间件

    • 客户端发起的任何请求,到达服务器之后,都会触发中间件,叫做全局生效的中间件
    • 通过app.use(中间件函数),即可定义一个 全局生效的中间件,示例代码如下:
        const express = require('express')
        const app = express()
        //定义一个中间件
        const c1 = function (req, res, next) {
            console.log('这是一个中间件函数')
            // 把流转关系,转交给下一个中间件或路由
            next()
        }
        //将cl函数注册为全局生效的中间件
        app.use(c1)
        
        app.get('/', (req, res) => {
            console.log('调用了/这个路由')
            res.send('home page')
        })
        app.post('/user', (req, res) => {
            console.log('调用了/user这个路由')
            res.send('user page')
        })
        app.listen('8088', () => {
            console.log('express server running is http://127.0.0.1:8088')
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    定义中间件简化形式

        const express = require('express')
        const app = express()
        // 定义全局中间件的简化形式
        app.use((req,res,next)=>{
            console.log('定义全局中间件的简化形式')
            next()
        })
        app.get('/', (req, res) => {
            console.log('调用了/这个路由')
            res.send('home page')
        })
        app.listen('8088', () => {
            console.log('express server running is http://127.0.0.1:8088')
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    中间件的作用

    • 多个中间件之间,共享一份req 和 res ,基于这样的特性,我们可以在上游的中间件中,统一的为req 或 res对象添加自定义的属性和方法,供下游的中间件或者路由使用。
        const express = require('express')
        const app = express()
        // 定义全局中间件的简化形式
        app.use((req, res, next) => {
        //    获取请求到达服务器的时间
        const  time = Date.now()
            //为 req 对象 拦截自定义属性,从而把时间共享给后面的所有路由
            req.startTime = time
            next()
        })
        app.get('/', (req, res) => {
            res.send('home page' + req.startTime)
        })
        app.post('/user', (req, res) => {
            res.send('user page' +req.startTime)
        })
        app.listen('8088', () => {
            console.log('express server running is http://127.0.0.1:8088')
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    定义多个全局中间件

    • 可以用app.use() 连续定义多个全局中间件,客户端请求到达服务器之后,会按照中间件的定义的先后顺序依次进行调用, 示例代码如下:
        /**
         *定义多个全局中间件
         * */
        const express = require('express')
        const app = express()
        //第一个全局中间件
        app.use(function (req, res, next) {
            console.log('第一个全局中间件')
            next()
        })
        //第二个全局中间件
        app.use(function (req, res, next) {
            console.log('第二个全局中间件')
            next()
        })
        //定义路由
        app.get('/', (req, res) => {
            res.send('home page')
        })
        app.listen('8088',()=>{
            console.log('express server running at http://127.0.0.1:8088')
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    局部定义的中间件

    • 不使用 app.use() 定义的中间件叫做 局部生效的中间件,代码示例如下:
      /**
       *定义局部生效的中间件
       * */
      const express = require('express')
      const app = express()
      const ct = (req,res,next)=>{
          console.log('局部生效中间件函数')
        next()
      }
      //定义路由
      app.get('/',ct, (req, res) => {
          res.send('home page')
      })
      app.post('/user', (req, res) => {
          res.send('user page')
      })
      app.listen('8088',()=>{
          console.log('express server running at http://127.0.0.1:8088')
      })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    定义多个局部中间件,代码示例如下:

        /**
         *定义多个局部中间件
         * */
        const express = require('express')
        const app = express()
        const ct1 = (req,res,next)=>{
            console.log('第一个局部中间件函数')
          next()
        }
        const ct2 = (req,res,next)=>{
            console.log('第二个局部中间件函数')
            next()
        }
        const ct3 = (req,res,next)=>{
            console.log('第三个局部中间件函数')
            next()
        }
        const ct4 = (req,res,next)=>{
            console.log('第四个局部中间件函数')
            next()
        }
        //定义路由
        app.get('/',ct1,ct2, (req, res) => {
            res.send('home page')
        })
        app.post('/user',[ct3,ct4], (req, res) => {
            res.send('user page')
        })
        app.listen('8088',()=>{
            console.log('express server running at http://127.0.0.1:8088')
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    使用中间件的注意事项

    • 一定要在路由之前注册中间件
    • 客户端发送过来的请求,可以连续调用多个中间件进行处理
    • 执行完中间件的业务代码之后,不要忘记调用next()函数
    • 为了防止代码逻辑混乱,调用next()函数之后不要再写额外的代码
    • 连续调用多个中间件时,多个中间件之间,共享 req 和 res 对象

    中间件的分类

    • 注意:除了错误级别的中间件,其他的中间件必须在路由之前配置
    应用级别的中间件
    • 通过 app.use()或者app.get()或app.post() 绑定在app示例上的中间件,叫做应用级别的中间件
    路由级别的中间件
    • 绑定到 express.Router() 实例上的中间件,叫做路由级别的中间件,它的用法和应用级别的中间件没有任何区别,只不过,应用级别的中间件绑定在app实例上,路由级别的中间件绑定在router实例上
    错误级别的中间件
    • 作用: 专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题
    • 格式: 错误级别中间件中的function处理函数中,必须有4个形参,形参顺序从前到后,分别是(err,req,res,next).
    • 注意: 错误级别的中间件,必须注册在所有路由之后
    • 代码实例如下:
    /**
     * 错误级别中间件
     * **/
    const  express = require('express')
    const app = express()
    //1.定义路由
    app.get('/',(req,res)=>{
    //   人为制造错误
        throw  new Error('服务器内部出现error')
        res.send('home page')
    })
    //2.定义错误级别的中间件,捕获整个项目中的异常错误,从而防止程序的崩溃
    app.use((err,req,res,next)=>{
        //2.1 在服务器中打印错误
        console.log('发生了错误'+err.message)
        //2.2 向客户端响应错误相关的内容
        res.send('Error'+err.message)
    })
    //调用 app.listen 方法,指定端口号,启动web服务器
    app.listen('8088',()=>{
        console.log('express server running at http://127.0.0.1:8088')
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    Express的内置中间件
    1. express.static 快速托管静态资源的内部中间件,例如:HTML文件,图片,CSS样式等(无兼容性)
    2. express.json 解析JSON格式的请求体数据,(有兼容性,仅在4.16.0+ 版本中使用)
    3. express.urlencoded 解析 URL-encoded 格式的请求体数据(有兼容性,仅在4.16.0+ 版本中使用)
    /**
     * 内置中间件的使用 express.json()和express.urlencoded({extended:false})
     * **/
    const  express = require('express')
    const app = express()
    //注意:除了错误级别的中间件,其他的中间件必须在路由之前配置
    // 通过express.json 这个中间件。解析表单中json 格式的数据
    // 通过express.urlencoded()这个中间件,来解析表单中url-encoded 格式的数据(解析 x-www-form-urlencoded 格式的表单数据)
    app.use(express.json())
    app.use(express.urlencoded({extended:false}))
    
    app.post('/user',(req,res)=>{
        //在服务器中,可以使用 req.body 这个属性,来接收客户端发送过来的请求体数据
        //默认情况下,如果不配置解析表单数据的中间件,则req.body 默认等于 undefined
        console.log(req.body)
        res.send('ok')
    })
    app.post('/book',(req,res)=>{
        //在服务器中,可以使用 req.body 这个属性,来接收客户端发送过来的请求体数据 和url-encoded 格式的数据
    
        console.log(req.body)
        res.send('bookok')
    })
    //调用 app.listen 方法,指定端口号,启动web服务器
    app.listen('8088',()=>{
        console.log('express server running at http://127.0.0.1:8088')
    })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    第三方的中间件
    • 非Express 官方内置的,而是由第三方提供出来的中间件,叫做第三方中间件,在项目中大家可以按需下载并配置第三方中间件,从而提高项目的开发效率
    • 例如使用body-parser 第三方中间件解析请求体数据
    • 输入 npm install body-parser 安装中间件
    • 使用require导入中间件
    • 调用 app.use ()注册并使用中间件
    • 使用方法如下:
        const  express = require('express')
        const app = express()
        //1导入解析数据的中间件body-parser
        const parser = require('body-parser')
        // 2.使用app.use 注册中间件
        app.use(parser.urlencoded({extended:false}))
        
        app.post('/book',(req,res)=>{
            //,如果不配置解析表单数据的中间件,则req.body 默认等于 undefined
            console.log(req.body)
            res.send('ok1')
        })
        //调用 app.listen 方法,指定端口号,启动web服务器
        app.listen('8088',()=>{
            console.log('express server running at http://127.0.0.1:8088')
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    自定义中间件

    • 在文件目录下创建两个js文件,自定义模块化拆分.js 和 conmon-body-parser.js
    • 在 自定义模块化拆分.js 文件中导入封装的中间件
    const express = require('express')
    const app = express()
    // 1.导入之间封装的中间件
    const custbodyparser =require('./conmon-body-parser')
    // 2.将自定义的中间件,注册为全局可用的中间件
    app.use(custbodyparser)
    app.post('/book', (req, res) => {
        res.send(req.body)
    })
    app.listen('8088', () => {
        console.log('express server running at http://127.0.0.1:8088')
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 在conmon-body-parser.js文件中进行封装中间件
    // 导入node.js 内置的 querystring 模块
    const qs = require('querystring')
    const bodyparser = (req, res, next) => {
        // 1.定义一个str字符串,专门用来存储客户端发送过来的请求数据
        let str = ''
        // 2.监听req 的data事件
        req.on('data', (chunk) => {
            str += chunk
        })
        // 3.监听req的 end事件
        req.on('end', () => {
            //在 str中存放的是完整的请求体数据
            console.log(str)
            //    todo:把字符串格式的请求体数据,解析成对象格式
            const body = qs.parse(str)
            console.log(body)
            req.body = body
            next()
        })
    }
    module.exports=bodyparser
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
  • 相关阅读:
    剖析虚幻渲染体系(14)- 延展篇:现代渲染引擎演变史Part 1(萌芽期)
    玉柴集团用USB Server对U盾远程安全管控
    【ARM 嵌入式 编译 Makefile 系列 15.1 -- arm gcc 与 Makefile 一块使用示例】
    Patroin源码修改八:初始化Opengauss
    存储器概述
    点评项目核心内容
    首饰饰品经营商城小程序的作用是什么
    今天遇到Windows 10里安装的Ubuntu(WSL)的缺点
    Linux02(J2EE项目部署与发布)
    句子嵌入: 交叉编码和重排序
  • 原文地址:https://blog.csdn.net/xxz_best/article/details/126728783