2022-02-27 Node.js Express框架学习笔记(三) 中间件(Middleware):局部中间件,应用级中间件,路由级中间件,错误处理中间件

本文详细介绍了Node.js Express框架中的中间件概念,包括中间件的本质、调用流程、作用以及分类。特别讨论了局部中间件、应用级中间件、路由级中间件和错误处理中间件的使用和示例,帮助开发者理解如何在不同场景下合理运用中间件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0.Express中间件的概念
定义

业务流程的中间处理环节

本质

一个function处理函数,参数:请求对象req,响应对象res,中间件next

app.use(function(req,res,next) {
	...
	next();
})
调用流程

当一个请求到达Express的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理。

next参数&next()函数
中间件函数的形参列表中,必须包含next参数,路由处理函数中只包含req和res.
next函数的作用:表示把流转关系转交给下一个中间件或路由。
是实现多个中间件连续调用的关键

意思就是没有next形参和调用next(),不能往下执行下一个回调函数

中间件的作用
  • 执行任何代码
  • 修改请求&响应对象
  • 终结请求&响应循环
  • 调用下一个中间件
中间件的分类
  • 应用级中间件
  • 路由级中间件
  • 错误处理中间件
  • 内置中间件
  • 第三方中间件
注意事项
1.一定要在路由之前注册中间件
2.客户端发送过来的请求,可以连续调用多个中间件进行处理
3.执行完中间件的业务代码之后,不要忘记调用 next() 函数
4.为了防止代码逻辑混乱,调用 next() 函数后不要再写额外的代码
5.连续调用多个中间件时,多个中间件之间,共享 req 和 res 对象
6.多个中间件只能在其中一个中间件中有一个res.send()语句,否则报错
1.局部生效的中间件

使用 app.use() 定义的中间件,叫做局部生效的中间件

示例
var func1 = (req, res, next) => {
    console.log('调用了局部生效的中间件');
    next();
}
var func2 = (req, res, next) => {
    console.log('调用了全局生效的中间件');
    next();
};
app.use(func2);//func2这个中间件在当前所有路由中自动调用生效
app.get('/', func1, (req, res) => { res.send('Home page.') }); // func1这个中间件只在当前路由中生效
app.get('/user', (req, res) => { res.send('User page.') });
2.应用级中间件(全局)

应用级中间件绑定到app对象,使用app.use()和app.METHOD(),
其中,METHOD表示需要处理的http请求的方法如get,post,put等等

app.use();
app.get();
app.post();
...
都可以注册中间件
语法
var express = require('express');
var app = express();
//这是一个没有挂载路径的中间件,应用的每个请求都会执行它
app.use(function(req, res, next) {
    console.log("hello world ");
    next();
});
//同理,如果中间件挂载路径,只会在此路径中调用
示例:把复用性高的路由改成应用级中间件
var express = require('express');
var app = express();
app.get("/", function(req, res) {
    res.send(`<html><h1>hello world</h1></html>`);
});
var func1 = function(req, res, next) {
    console.log("验证token..");
    var isVal = true;
    if (isVal) {
        next();
    } else {
        res.send("error");
    }
};

// 路由句柄:多个回调写法
// app.get('/list', function(req, res, next) {
//     console.log('验证token ...');
//     next(); //指定next对象
// }, function(req, res) { //第二个回调函数
//     res.send('list');
// });

// 路由句柄:函数和回调混合写法
// app.get('/list', func1, function(req, res) { 
//     res.send('list');
// });

// 应用级中间件:把func1做成应用级中间件,挂载在app上,
//就不需要每个分页面再引用一次func1,因为会默认调用
app.use(func1);
app.get("/list", function(req, res) { 
    res.send('list');
});
// 设置监听
app.listen(3000, function() {
    console.log("server connect...");
});
应用级中间件的注册顺序

app.use(func1);的位置很重要,因为是从上到下的执行顺序,
由于应用级中间件"不用挂载路径,应用的每个请求都会执行它"的这个特点,
我们应该把不想调用中间件的写在前面,需要调用的写在后面

// home page在应用级中间件上面,所以返回根目录不会调用
app.get("/", function(req, res) {
    res.send("home page");
});
var func1 = function(req, res, next) {
    console.log("验证token...");
    next();
};
app.use(func1);
// list page在应用级中间件下面,所以返回/list就会调用
app.get("/list", function(req, res) {
    res.send("list page");
});
3.路由级中间件

路由级中间件与应用级中间件是一样的,只是前者的绑定对象是在express.Router()

语法
var route=express.Route();
var app=express();
router.use((req,res,next)=>{
	...
	next();
}));
示例一:应用级中间件和路由级中间件的对比例子

router01.js

var express = require("express");
var router = express.Router();
//路由级别
router.get("/", function(req, res) {
    res.send("home page");
});
router.get("/login", function(req, res) {
    res.send("login page");
});

// 导出路由
module.exports = router;

index01.js

var express = require("express");
var app = express();
// 导入路由中间件
var indexRouter = require("./router/router01");//相对路径
//应用级别
app.use(function(req, res, next) {//中间件注册
    console.log("验证token...");
    next();
});

// app.use("/",路由中间件);
app.use("/", indexRouter);//此处路径若是"/api",则只能在127.0.0.1:3000/api/login显示

app.listen(3000, function(req, res) {
    console.log("server connect...");
});

结果:127.0.0.1:3000127.0.0.1:3000/login都能正常显示

示例二:路由中间件只处理单一功能/页面

router/homeRouter.js

var express = require("express");
var router = express.Router();
router.get("/", function(req, res) {
    res.send("home page");
});
// 导出路由
module.exports = router;

router/loginRouter.js

var express = require("express");
var router = express.Router();
router.get("/login", function(req, res) {
    res.send("login page");
});
// 导出路由
module.exports = router;

index.js

var express = require("express");
var app = express();
// 导入路由中间件
var homeRouter = require("./router/homeRouter");
var loginRouter = require("./router/loginRouter");
//注册应用级中间件
app.use("/", homeRouter);
app.use("/", loginRouter);
//设置监听
app.listen(3000, function(req, res) {
    console.log("server connect...");
});

结果同上例
另一种写法:index01.js

var express = require("express");
const app = express();
//写一起
app.use(require("./router/homeRouter"), require("./router/loginRouter"));
app.listen(3000, function() {
    console.log("server connect...");
});
4.错误处理中间件

错误中间件有四个参数,err参数负责处理错误

语法
app.use(function(err,req,res,next){
	res.status(500).send("error!");//根据状态码识别响应错误
});
示例:处理浏览器地址访问不存在目录的错误
app.use(function(req, res) {
    // console.log(err.stack);
    res.status(404).send(`<html><h2>404 not found</h2></html>`);
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端OnTheRun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值