express中间件请求顺序,中间件next请求流程走向
发布于 作者:苏南大叔 来源:程序如此灵动~本文主要说明express
的中间件的请求顺序问题,中间件如何加载,如何控制页面的流程走向,着重说明的是顺序。
苏南大叔的“程序如此灵动”博客,记录苏南大叔和计算机代码的故事。测试环境:node@16.14.2
,express@4.18.2
。
定义一个中间件
中间件的定义很容易,不容易的是内部的逻辑。中间件可以是async
,也可以是普通的函数。
(req, res, next) => {
//...
next();
//...
}
async (req, res, next) => {
//...
await next();
//...
}
如果是单独文件的话,还需要模块导出:
module.exports = (req, res, next) => {
//...
next();
//...
}
module.exports = async (req, res, next) => {
//...
await next();
//...
}
注意这里module.exports
是个commonjs
的模块写法,在主程序中可以require
也可以import
。
res
和req
req
是客户端请求,res
是服务器端响应。所以,是req
先end
,res
才开始构造,再end
。req.body
和res.body
是不同的。先分析获取req.body
,再构造发送res.body
。
res.send()
只能send
一次,其会引发res
的end
事件。所以,在res.send()
之后,再输出的话,就会引发错误。例如:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
Error: Can't set headers after they are sent.
先res.sendFile()
再res.send()
不会引发错误。但是,只会有后面发送的数据是生效的。
next()
next()
是中间件之间相互沟通的桥梁。必须有next()
,否则页面就可能会出现没有响应或者中间件没有执行的问题。但是,next()
有三个变种:
变种 | 说明 |
---|---|
next() | 无 |
await next() | 需要配置async |
return next() | 当前中间件里面,return之后的的逻辑就无法执行了,不影响其他中间件里面的逻辑。 |
next()
的言外之意就是:执行接下来的中间件,包括app.get()
或者app.post()
的主体逻辑。
async
和await
这个中间件到底是个异步的,还是个同步的呢? 答案是两者都可以。但是,如果要await next()
的话,就只能配合async
。这个道理大家都懂。参考文章:
生效途径
中间件可以是全局的中间件,还可以是局部的中间件。如果注册为全局的中间件的话,就需要慎重考虑了。因为中间件之间可能会有冲突竞争关系,会导致不可抗的失败因素。
用作全局中间件
app.use(中间件)
这样的操作,所有的页面都会经过这些中间件的过滤。
用作路由中间件
app.get("/test.html", 中间件, function (req, res) {
//...
});
这种情况下,对应的中间件只会处理这个路由所在的文件请求。路由里面的中间件可以是个变量,也可以是个数组,效果上和使用多个app.use()
效果类似。
执行顺序
整体来说,req
=>res
。但是,req
和res
结束于哪个中间件里面,不一定。或者说req
可能结束于多个中间件里面,因为每个中间件都可以监控req
的end
事件。res
的end
事件,可以由res.send()
来引发。任何一个插件(包括路由里面)res.send()
之后,就意味着输出通道的结束,也就是res
的end
事件。后续逻辑可以执行,但是不可以输出。
先顺序执行app.use()
全局定义的中间件,再执行顺序app.get()
或者app.post()
定义的中间件,然后执行app.get()
或者app.post()
。通过next()
进行串联,所以,这些中间件内的放在next()
之后的逻辑,就会在最后执行了。
因为一般来说,app.get()
或者app.post()
会有输出。之后才会去执行中间件里面,next()
之后的逻辑。那么,能做的事情就很有限了,因为已经输出结果了。
执行顺序上,先【顺序】执行next()
之前的逻辑,在【逆序】执行next()
之后的逻辑。变数有两个:
return next()
。当前中间件逻辑马上结束,不影响后续中间件逻辑。await next()
。之后的逻辑在所有的逆序里面优先级提到最后,多个await
,优先级顺序排到最后。(整体上来说,就是把所有的await
都跳出来放到最后,他们之间相对顺序不变。)
测试代码如下:
let express = require("express");
let app = express();
let server = app.listen(3222, function () {
var port = server.address().port;
console.log(`访问地址为 http://localhost:${port}`);
});
app.use((req, res, next) => {
console.log("1");
next();
console.log("8");
})
app.use(async (req, res, next) => {
console.log("2");
await next();
console.log("7");
})
app.use(async (req, res, next) => {
console.log("3");
return next();
console.log("6");
})
let m1 = require("./middlewares/middle1");
let m2 = require("./middlewares/middle2");
let m3 = require("./middlewares/middle3");
let middlewares = [
m1, m2, m3
];
app.get("/test.html", middlewares, function (req, res) {
console.log("4");
res.send("sunan");
// res.send("苏南大叔");
console.log("5");
});
middlewares/middle1.js
:
module.exports = (req, res, next) => {
var path = require('path');
var scriptName = path.basename(__filename);
console.log(scriptName+"前");
next();
console.log(scriptName+"后");
}
middlewares/middle2.js
【async+await】:
module.exports = async (req, res, next) => {
var path = require('path');
var scriptName = path.basename(__filename);
console.log(scriptName + "前");
await next();
console.log(scriptName + "后");
}
middlewares/middle3.js
【return】:
module.exports = (req, res, next) => {
var path = require('path');
var scriptName = path.basename(__filename);
console.log(scriptName + "前");
return next();
console.log(scriptName + "后");
}
执行顺序是这样的:
1 2 3 middle1.js前 middle2.js前 middle3.js前
4 5 middle1.js后 8 middle2.js后 7
相关链接
结束语
更多express
的相关经验文章,请点击:
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。