中间件
- 内置中间件:
app.use(express.urlencoded({ extended: false })); 处理POST请求的
app.use(express.static('./webapp')); 当前app.js同目录下webapp文件夹作为静态资源访问
- 第三方中间件:
比如multer、express-jwt、express-session、....
【实际开发中,自己写中间件的机会并不大,一般都有对应的第三方中间件。】
介绍
-
中间件(Middleware ),特指业务流程的中间处理环节。
-
中间件,是express最大的特色,也是最重要的一个设计
-
很多第三方模块,都可以当做express的中间件,配合express,开发更简单。
-
一个express应用,是由各种各样的中间件组合完成的
-
为了理解中间件,我们先来看一下我们现实生活中的自来水厂的净水流程:
- 自来水厂从获取水源到净化处理交给用户,中间经历了一系列的处理环节
- 我们称其中的每一个处理环节就是一个中间件
- 这样做的目的既提高了生产效率也保证了可维护性。
中间件,本质上就是一个函数;中间件函数中有四个基本参数, err、req、res、next
- err:如果带有err参数,并且中间件函数给了全部的4个参数,那么这个中间件有特殊的用法,表示错误处理中间件,错误处理中间件,可以处理前面所有的中间件抛出的错误。
- req:请求相关的对象
- res:响应相关的对象
- next:它是一个函数,某些时候,可以省略
next()
-
无参数:执行完当前中间件,往下一个匹配到中间件函数执行,直到遇见
res.send();
const express = require("express"); const app = express(); app.listen(3000, () => console.log("启动成功, http://localhost:3000")); // 定义中间件函数 - 函数体 // 给服务器注册全局生效的中间件 app.use();无论是get 还是post请求都会经过这个中间件处理 app.use(function(req, res, next){ console.log("我是一个中间件函数, 我处理完了1"); // 调用next函数, 才会传递给下一个函数处理(按照编写顺序) next(); }); app.use(function(req, res, next){ console.log("我是一个中间件函数, 我处理完了2"); next(); }); // 路由 - 处理完毕 - 返回响应数据 app.get("/api/list", (req, res) => { res.send("get请求 /api/list"); }) app.get("/api/book", (req, res) => { res.send("get请求 /api/book"); })
-
应用: 所有的接口,加快给用户返回服务器的系统时间
-
曾经:接口多了就显得很肉;
var momentObj = require('moment'); app.get("/api/getbook", (req, res) => { let nowDate = momentObj.format("YYYY-MM-DD HH:mm:ss"); res.send({ msg: "get方式/api/getbooks被访问了", time: nowDate }) }) app.post("/api/addbook", (req, res) => { let nowDate = momentObj.format("YYYY-MM-DD HH:mm:ss"); res.send({ msg: "post方式/api/addbook", time: nowDate }) })
-
中间件设计:
// 可以提到公共的中间件里来写 - 因为所有的中间件都共享同一个req和 res对象 app.use((req, res, next) => { res.nowDate = momentObj.format("YYYY-MM-DD HH:mm:ss"); // new Date() 获取的是标准时间, 比北京时间少8小时 next(); }) app.get("/api/getbook", (req, res) => { res.send({ msg: "get方式/api/getbooks被访问了", time: res.nowDate }) }) app.post("/api/addbook", (req, res) => { res.send({ msg: "post方式/api/addbook", time: res.nowDate }) })
next(?)
-
给next传递参数:表示发生了错误;将会越过后续所有的中间件,直接进入最后的错误处理中间件;
// 自定义中间件 app.use((req, res, next) => { next('发生错误了'); }); app.get('/get/books', (req, res, next) => { res.send("给前端 书籍的 数据"); }); app.get('/get/sts', (req, res, next) => { res.send("给前端 学生的 数据"); }); // 最后 用于错误处理中间件 app.use((err, req, res, next) => { res.send({ status: 500, message: err }) });
// 自定义中间件 app.use((req, res, next) => { // 如果没有数据 if (req.query.token == "") { next("没有token的错误"); } // else { next(); } }); app.get('/get/sts', (req, res, next) => { res.send("给前端 学生的 数据"); }); app.get('/get/books', (req, res, next) => { res.send("给前端 图书的 数据"); }); app.use((err, req, res, next) => { res.send({ status: 500, message: err }) }); // err 为next中的值
其他用法
```
// app.use 中的中间件,可以处理所有的GET请求和所有的POST请求,没有指定路径,那么处理所有接口
app.use(中间件函数);
app.use(中间件函数, 中间件函数, 中间件函数 .....);
// 下面的中间件函数,只处理 /api 开头的接口
app.use('/api', 中间件函数);
// 下面的中间件(了解),只为当前接口 /my/userinfo 这个接口服务
app.get('/my/userinfo', 中间件函数);
app.get('/my/userinfo', 中间件函数, 中间件函数, 中间件函数, 中间件函数 .....);
// 下面的几个中间件,是处理 /api/login 接口的
app.post('/api/login', 中间件函数)
app.post('/api/login', 中间件函数, 中间件函数, 中间件函数, 中间件函数 .....);
```