文章目录
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:3000
和127.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>`);
});