我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

本文主要说明express的中间件的请求顺序问题,中间件如何加载,如何控制页面的流程走向,着重说明的是顺序。

苏南大叔:express中间件请求顺序,中间件next请求流程走向 - express-middleware
express中间件请求顺序,中间件next请求流程走向(图6-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔和计算机代码的故事。测试环境:node@16.14.2express@4.18.2

定义一个中间件

中间件的定义很容易,不容易的是内部的逻辑。中间件可以是async,也可以是普通的函数。

(req, res, next) => {
  //...
  next();
  //...
}
async (req, res, next) => {
  //...
  await next();
  //...
}

苏南大叔:express中间件请求顺序,中间件next请求流程走向 - code-1
express中间件请求顺序,中间件next请求流程走向(图6-2)

如果是单独文件的话,还需要模块导出:

module.exports = (req, res, next) => {
  //...
  next();
  //...
}
module.exports = async (req, res, next) => {
  //...
  await next();
  //...
}
注意这里module.exports是个commonjs的模块写法,在主程序中可以require也可以import

resreq

req是客户端请求,res是服务器端响应。所以,是reqendres才开始构造,再endreq.bodyres.body是不同的。先分析获取req.body,再构造发送res.body

res.send()只能send一次,其会引发resend事件。所以,在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()不会引发错误。但是,只会有后面发送的数据是生效的。

苏南大叔:express中间件请求顺序,中间件next请求流程走向 - res-send
express中间件请求顺序,中间件next请求流程走向(图6-3)

next()

next()是中间件之间相互沟通的桥梁。必须有next(),否则页面就可能会出现没有响应或者中间件没有执行的问题。但是,next()有三个变种:

变种说明
next()
await next()需要配置async
return next()当前中间件里面,return之后的的逻辑就无法执行了,不影响其他中间件里面的逻辑。

next()的言外之意就是:执行接下来的中间件,包括app.get()或者app.post()的主体逻辑。

苏南大叔:express中间件请求顺序,中间件next请求流程走向 - code-2
express中间件请求顺序,中间件next请求流程走向(图6-4)

asyncawait

这个中间件到底是个异步的,还是个同步的呢? 答案是两者都可以。但是,如果要await next()的话,就只能配合async。这个道理大家都懂。参考文章:

生效途径

中间件可以是全局的中间件,还可以是局部的中间件。如果注册为全局的中间件的话,就需要慎重考虑了。因为中间件之间可能会有冲突竞争关系,会导致不可抗的失败因素。

用作全局中间件

app.use(中间件)

这样的操作,所有的页面都会经过这些中间件的过滤。

用作路由中间件

app.get("/test.html", 中间件, function (req, res) {
    //...
});

这种情况下,对应的中间件只会处理这个路由所在的文件请求。路由里面的中间件可以是个变量,也可以是个数组,效果上和使用多个app.use()效果类似。

执行顺序

整体来说,req=>res。但是,reqres结束于哪个中间件里面,不一定。或者说req可能结束于多个中间件里面,因为每个中间件都可以监控reqend事件。resend事件,可以由res.send()来引发。任何一个插件(包括路由里面)res.send()之后,就意味着输出通道的结束,也就是resend事件。后续逻辑可以执行,但是不可以输出。

先顺序执行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");
});

苏南大叔:express中间件请求顺序,中间件next请求流程走向 - code-3
express中间件请求顺序,中间件next请求流程走向(图6-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 + "后");
}

苏南大叔:express中间件请求顺序,中间件next请求流程走向 - code-4
express中间件请求顺序,中间件next请求流程走向(图6-6)

执行顺序是这样的:

1  2  3  middle1.js前  middle2.js前  middle3.js前 
4     5  middle1.js后  8             middle2.js后   7

相关链接

结束语

更多express的相关经验文章,请点击:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   express