Appearance
express 中间件
express 中间件初识
中间件作用:多个中间件之间,共享同一份 req 和 res。在上游的中间件中,可以统一为 req 或 res 对象添加自定义的属性或方法,供下游的中间件或路由进行使用
1. 全局中间件
客户端发起的任何请求,到达服务器之后,都会触发的中间件
js
// 定义中间件函数
const mw = (req, res, next) => {
console.log("hello 中间件");
next();
};
// 注册中间件
app.use(mw);
2. 定义多个全局中间件
客户端请求到达服务器之后,会按照中间件定义的先后顺序依次进行调用
js
// 中间件1
app.use((req, res, next) => {
console.log("我是中间件1");
next();
});
// 中间件2
app.use((req, res, next) => {
console.log("我是中间件2");
next();
});
// 当请求路由,会依次触发上面的中间件
app.get("/user/list", (req, res) => {
res.send("user list");
});
3. 定义局部中间件
不使用 app.use()
定义的中间件,叫做局部生效的中间件
js
// 定义中间件
const mw = (req, res, next) => {
console.log("我是局部中间件");
};
// mw中间件只会在此路由中生效
app.get("/about", mw, (req, res) => {
res.send("调用成功");
});
// mw不会影响下面的路由
app.get("/home", (req, res) => {
res.send("调用成功");
});
4. 定义多个局部中间件
js
// 写法1
app.get("/about", mw1, mw2, (req, res) => {
res.send("调用成功");
});
// 写法2
app.get("/about", [mw1, mw2], (req, res) => {
res.send("调用成功");
});
5. 使用中间件注意事项
- 一定要在路由之前注册中间件
- 客户端发送过来的请求,可以连续调用多个中间件进行处理
- 执行完中间件的业务代码之后,需要调用
next()
函数 - 为了防止代码逻辑混乱,调用
next()
函数后不要再写额外的代码 - 连续调用多个中间件时,多个中间件之间,共享 req 和 res 对象
中间件的分类
1. 应用级别中间件
通过 app.use() 或 app.get() 或 app.post() ,绑定到 app 实例上的中间件,叫做应用级别的中间件
js
const mw = (req, res, next) => {
next();
};
// 全局
app.use(mw);
// 局部
app.get("/", mw, (req, res) => {
res.send("hello");
});
2. 路由级别中间件
绑定到 express.Router() 实例上的中间件,叫做路由级别的中间件
js
const app = express();
const router = express.Router();
// 路由级别中间件
router.use((req, res, next) => {
console.log("hello");
next();
});
app.use(router);
3. 错误级别中间件
专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题
- 格式:必须有 4 个形参,形参顺序从前到后,分别是 (err, req, res, next)
- 注意:错误级别的中间件,必须注册在所有路由之后
js
app.get("/", (req, res) => {
throw new Error("服务器错误");
res.send("hello");
});
app.use((err, req, res, next) => {
// 服务器打印错误消息
console.log("错误:" + err.message);
// 向客户端发送错误信息
res.send("error" + err.message);
next();
});
4. express 内置中间件
express.static
快速托管静态资源的内置中间件express.json
解析 JSON 格式的请求体数据express.urlencoded
解析 URL-encoded 格式的请求体数据
js
// 配置解析application/json 格式的数据
app.use(express.json());
//配置解析application/x-www-form-urlencoded格式的数据
app.use(express.urlencoded({ extended: false }));
5. 第三方中间件
使用步骤:
- npm i xxxx 安装依赖
- 使用 require 导入
- 调用 app.use()注册使用
6. 自定义中间件
6.1. 监听 req 的 data 事件,获取客户端发送到服务器的数据
如果数据量比较大,无法一次性发送完毕,则客户端会把数据切割后,分批发送到服务器。所以 data 事件可能会触发多次,每一次触发 data 事件时,获取到数据只是完整数据的一部分,需要手动对接收到的数据进行拼接。
js
// 定义变量,存储客户端发送过来的请求体数据
let str = "";
监听req对象的data事件;
req.on("data", (chunk) => {
// 拼接请求体数据
str += chunk;
});
6.2. 监听 req 的 end 事件
当请求体数据接收完毕之后,会自动触发 req 的 end 事件。可以在 req 的 end 事件中,拿到并处理完整的请求体数据
js
// 监听 req 对象的 end 事件(请求体发送完毕后自动触发)
req.on("end", () => {
// 拿到完整请求体数据
console.log(str);
});
6.3 使用 querystring 模块解析请求体数据
Node.js 内置 querystring 模块,用来处理查询字符串。通过这个模块提供的 parse() 函数,可以把查询字符串,解析成对象格式
js
const qs = require("querystring");
const body = qs.parse(str);
6.4. 将解析出来的数据对象挂载为 req.body
上游的中间件和下游的中间件及路由之间,共享同一份 req 和 res。因此,将解析出来的数据,挂载为 req 的自定义属性,命名为 req.body,供下游使用
js
req.on("end", () => {
const body = qs.parse(str);
req.body = body;
next();
});
6.5. 将自定义中间件封装为模块
custom.js
js
const qs = require('querystring')
function customParser = (req,res,next){/* .... */}
module.exports = customParser
app.js
js
const customParser = require("./customParser");
// 注册使用
app.use(customParser);