Node.js | express 中间件详解(应用级 | 路由级 | 内置 | 第三方)

时间:2022-10-15 13:53:14

Node.js | express 中间件详解(应用级 | 路由级 | 内置 | 第三方)


????️ NodeJS专栏:Node.js从入门到精通
????️ 博主的前端之路(源创征文一等奖作品):前端之行,任重道远(来自大三学长的万字自述)
????️ TypeScript知识总结:TypeScript 学习笔记(十万字超详细知识点总结)
????‍???? 个人简介:大三学生,一个不甘平庸的平凡人????
???? 你的一键三连是我更新的最大动力❤️!



???? 前言

Express 是一个自身功能极简,完全是由路由中间件构成一个的 web 开发框架:从本质上来说,一个 Express 应用就是在调用各种中间件

中间件(Middleware) 是一个函数,它可以访问请求对象(request object (req)), 响应对象(response object (res)), 和 web 应用中处于请求-响应循环流程中的中间件,一般被命名为 next 的变量。

function (req, res, next) {
  // 三个参数:req, res, next
  console.log('我是一个中间件')
  next()
}

中间件的功能包括:

  • 执行任何代码。
  • 修改请求和响应对象。
  • 终结请求-响应循环。
  • 调用堆栈中的下一个中间件。

如果当前中间件没有终结请求-响应循环,则必须调用 next() 方法将控制权交给下一个中间件,否则请求就会挂起。

Express 应用可使用如下几种中间件:

  • 应用级中间件
  • 路由级中间件
  • 错误处理中间件
  • 内置中间件
  • 第三方中间件

使用可选的挂载路径,可在应用级别或路由级别装载中间件。另外,你还可以同时装载一系列中间件函数,从而在一个挂载点上创建一个子中间件

1️⃣ 应用级中间件

简单来说,应用级中间件就是绑定到应用级别(app)上的中间件

应用级中间件使用 app.use()app.METHOD()绑定到 app 对象 , 其中, METHOD 是需要处理的 HTTP 请求的方法,例如 get, put, post等等,全部小写。例如:

var app = express()

// 不指定挂载路径,则匹配所有路径
app.use(function (req, res, next) {
  console.log('无挂载路径的应用级中间件')
  next()
})

上边是一个没有挂载路径的应用级中间件,应用的每个请求都会执行该中间件(函数),即用户访问的任何路由都会触发这个函数的执行。

当然我们也可以去指定应用级中间件的挂载路径:

// 指定挂载路径为/home,则只匹配/home
app.use("/home", function (req, res, next) {
    console.log("/home路径的应用级中间件");
    next();
});

这样就只有匹配到/home时,上述中间件才会执行。

使用app.METHOD()挂载多个路由处理函数实际就是指定了挂载路径的应用级中间件的应用:

var app = express()

// isToken是一个中间件
const isToken = (req, res, next) => {
   console.log("我相当于是一个中间件!");
   next()
};

// getUser是路由的处理函数,并不是中间件
const getUser = (req, res) => {
    res.send("匹配 / 路径的get请求");
}

// 使用app.get时指定了/user路径并挂载了isToken中间件,则这里的isToken就相当于是应用级的中间件了
app.get("/user", [isToken], getUser);

Node.js | 你不知道的 express 路由使用技巧一文中我们提到了一个路由多处理函数的应用:token验证,我们现在可以使用应用级中间件去改造它一下:

// 不需要token验证
app.get("/login", (req, res) => {
    res.send("登录");
});

// 验证token的函数(可插拔,可复用的中间件)
const isToken = (req, res, next) => {
    // 验证token是否过期,isVaild代表token是否有效
    // 一些操作
    const isVaild = true; // 假设验证通过
    
    if (isVaild) {
        // 验证通过了就调用next向下执行
        console.log("token验证通过");
        // 如果想要在回调函数之间传递数据,我们可以选择将数据挂载到res参数上
        res.ailjx = "海底烧烤店ai";
        next();
    } else {
        // 返回错误
        // 这里res.send后后面的回调函数就不会再执行了
        res.send("token验证失败!");
    }
};

// app.use用来注册全局的应用中间件,因为JS代码是从上向下执行,所以app.use之后的路由才会受该应用中间件(isToken)的影响,所以需要注意这个app.use的使用地方
app.use(isToken) // app.use之前不受isToken影响

// 只有token有效时才生效的接口
app.get("/home", (req, res) => {
    // 返回数据内容
    // res.ailjx:获取验证token的函数在res上绑定的数据
    res.send("home" + res.ailjx);
});

app.get("/user", (req, res) => {
    // 返回数据内容
    res.send("user");
});

对比 Node.js | 你不知道的 express 路由使用技巧 一文中的应用,这里我们将isToken这个中间件在需要token验证的路由,不需要token验证的路由使用app.use全局挂载,这样就不需要在/home/user中单独注册添加isToken了。

2️⃣ 路由级中间件

路由级中间件和应用级中间件一样,只是它绑定的对象为express.Router(),在Node.js | 你不知道的 express 路由使用技巧 一文中我们已经详细介绍过,大家可以跳转查看,这里就不再多说啦。

3️⃣ 错误处理中间件

错误处理中间件和其他中间件定义类似,只是要使用 4 个参数 (err, req, res, next),比普通的中间件多了一个err参数:

// 错误处理中间件:错误处理程序
app.use(function (err, req, res, next) {
    console.error(err);
    // status 设置状态码
    res.status(404).send("找不到页面!" + err);
});

错误处理中间件顾名思义就是捕获错误并进行处理的中间件,但需要注意的是,它并不会捕获未定义的路由!

const express = require("express");
const app = express();

// 错误处理中间件:错误处理程序
app.use(function (err, req, res, next) {
    console.error(err);
    // status 设置状态码
    res.status(404).send("找不到页面!" + err);
});

app.listen(3000, () => {
    console.log("express启动!");
});

上面的代码中我们并没有去定义任何路由,就只是挂载了一个错误处理中间件,现在我们启动该服务器随便访问一个路由:

Node.js | express 中间件详解(应用级 | 路由级 | 内置 | 第三方)

可以看到我们的错误处理中间件并没有执行,那用户访问未定义的路由时我们怎么去捕获呢?这就可以使用前面说到的应用级中间件:

const express = require("express");
const app = express();

// 定义你的一些路由

// 应用级中间件:捕获未定义的路由
app.use(function (req, res, next) {
    // status 设置状态码
    res.status(404).send("找不到页面!");
});

app.listen(3000, () => {
    console.log("express启动!");
});

Node.js | express 中间件详解(应用级 | 路由级 | 内置 | 第三方)

另一个问题就是,错误处理中间件在什么情况下才会执行?

当中间件调用next并向其传入非routerouter的参数时,会调用错误处理中间件,next中的参数会传入到错误处理中间件的err参数。

next中传入routerouter的参数时会略过其他路由回调函数

Node.js | express 中间件详解(应用级 | 路由级 | 内置 | 第三方)

注意: 由于JS代码是从上向下执行的,所以错误处理中间件和上面提到的用来捕获未定义路由的应用级中间件通常是放到代码的最下边(app.listen之前)

4️⃣ 内置中间件

express.staticExpress 唯一内置的中间件。它基于 serve-static,负责在 Express 应用中托管静态资源

每个应用可有多个静态目录。

app.use(express.static('public'))

将静态资源文件所在的目录作为参数传递给 express.static 中间件就可以提供静态资源文件的访问了。

例如,假设在 public 目录放置了一个index.html,我们就可以直接通过http://localhost:3000/index.html来访问它:

Node.js | express 中间件详解(应用级 | 路由级 | 内置 | 第三方)

所有文件的路径都是相对于存放目录的,因此,存放静态文件的目录名不会出现在 URL 中

如果你的静态资源存放在多个目录下面,你可以多次调用 express.static 中间件:

app.use(express.static('public'))
app.use(express.static('files'))

访问静态资源文件时,express.static 中间件会根据目录添加的顺序查找所需的文件。

如果你希望所有通过 express.static 访问的文件都存放在一个“虚拟(virtual)”目录(即目录根本不存在)下面,可以通过为静态资源目录指定一个挂载路径的方式来实现,如下所示:

app.use('/static', express.static('public'))

现在,你就可以通过带有 “/static” 前缀的地址来访问 public 目录下面的文件了:

Node.js | express 中间件详解(应用级 | 路由级 | 内置 | 第三方)

5️⃣ 第三方中间件

Express还具有很多的第三方中间件供我们下载使用,我们只需通过npm安装所需功能的中间件,并在应用中加载即可(可以在应用级加载,也可以在路由级加载)。

下面的例子安装并加载了一个解析 cookie 的中间件: cookie-parser

安装:

npm install cookie-parser

加载使用:

var express = require('express')
var app = express()
var cookieParser = require('cookie-parser')

// 加载用于解析 cookie 的中间件
app.use(cookieParser())

???? 结语

博主的Node.js从入门到精通专栏正在持续更新中,关注博主订阅专栏学习Node不迷路!

如果本篇文章对你有所帮助,还请客官一件四连!❤️

Node.js | express 中间件详解(应用级 | 路由级 | 内置 | 第三方)