Maison > Article > interface Web > Que signifie le middleware dans nodejs
Dans nodejs, le middleware fait principalement référence à la méthode qui encapsule le traitement détaillé de toutes les requêtes HTTP. C'est la méthode de traitement depuis l'initiation de la requête HTTP jusqu'à la fin de la réponse. Le comportement du middleware est similaire au principe de fonctionnement des filtres en Java, qui consiste à laisser le filtre le gérer avant d'entrer dans un traitement métier spécifique.
L'environnement d'exploitation de ce tutoriel : système windows7, nodejs version 12.19.0, ordinateur Dell G3.
Dans NodeJS, le middleware fait principalement référence à la méthode qui encapsule tous les détails des requêtes Http. Une requête Http comprend généralement beaucoup de travail, comme la journalisation, le filtrage IP, les chaînes de requête, l'analyse du corps de la requête, le traitement des cookies, la vérification des autorisations, la vérification des paramètres, la gestion des exceptions, etc., mais pour les applications Web, elles ne veulent pas être exposé à tant de traitements détaillés, un middleware est donc introduit pour simplifier et isoler les détails entre cette infrastructure et la logique métier, afin que les développeurs puissent se concentrer sur le développement commercial pour atteindre l'objectif d'améliorer l'efficacité du développement.
Le comportement du middleware est similaire au principe de fonctionnement des filtres en Java, qui consiste à laisser le filtre le gérer avant d'entrer dans un traitement métier spécifique. Son modèle de travail est présenté dans la figure ci-dessous.
const middleware = (req, res, next) => { // TODO next() }
Méthode 1
Définissez trois middleware simples comme suit : const middleware1 = (req, res, next) => {
console.log('middleware1 start')
next()
}
const middleware2 = (req, res, next) => {
console.log('middleware2 start')
next()
}
const middleware3 = (req, res, next) => {
console.log('middleware3 start')
next()
}
// 中间件数组
const middlewares = [middleware1, middleware2, middleware3]
function run (req, res) {
const next = () => {
// 获取中间件数组中第一个中间件
const middleware = middlewares.shift()
if (middleware) {
middleware(req, res, next)
}
}
next()
}
run() // 模拟一次请求发起
Exécutez le code ci-dessus, vous pouvez voir les résultats suivants : middleware1 start
middleware2 start
middleware3 start
S'il y a une opération asynchrone dans le middleware, elle doit se terminer à la fin du processus d'opération asynchrone Appelez ensuite la méthode next()
, sinon le middleware ne pourra pas être exécuté en séquence. Réécrire le middleware middleware2 :
const middleware2 = (req, res, next) => { console.log('middleware2 start') new Promise(resolve => { setTimeout(() => resolve(), 1000) }).then(() => { next() }) }
Le résultat de l'exécution est le même qu'avant, mais le middleware3 sera exécuté une fois le middleware2 terminé de manière asynchrone.
middleware1 start middleware2 start middleware3 start
Certains middleware doivent non seulement être exécutés avant le traitement métier, mais doivent également être exécutés après le traitement métier, comme le middleware de journalisation qui compte le temps. Dans le cas de la méthode 1, les autres codes du middleware actuel ne peuvent pas être exécutés en tant que rappels lorsque next()
est une opération asynchrone. Par conséquent, les opérations ultérieures de la méthode next()
peuvent être encapsulées dans un objet Promise
, et le middleware peut être complété à l'aide de next.then() Rappel après la fin du traitement commercial. Réécrivez la méthode <code>run()
comme suit :
function run (req, res) { const next = () => { const middleware = middlewares.shift() if (middleware) { // 将middleware(req, res, next)包装为Promise对象 return Promise.resolve(middleware(req, res, next)) } } next() }
La méthode appelante du middleware doit être réécrite comme : next()
方法,否则中间件不能按顺序执行。改写middleware2中间件:
const middleware1 = (req, res, next) => { console.log('middleware1 start') // 所有的中间件都应返回一个Promise对象 // Promise.resolve()方法接收中间件返回的Promise对象,供下层中间件异步控制 return next().then(() => { console.log('middleware1 end') }) }
执行结果与之前一致,不过middleware3会在middleware2异步完成后执行。
const middleware1 = (req, res, next) => { console.log('middleware1 start') // 所有的中间件都应返回一个Promise对象 // Promise.resolve()方法接收中间件返回的Promise对象,供下层中间件异步控制 return next().then((res) => { console.log("1",res) return 'middleware1 end'; }) } const middleware2 = (req, res, next) => { console.log('middleware2 start') // 所有的中间件都应返回一个Promise对象 // Promise.resolve()方法接收中间件返回的Promise对象,供下层中间件异步控制 // console.log("next()",next()) return next().then((res) => { console.log("2",res) return 'middleware2 end' }) } const middleware3 = (req, res, next) => { console.log('middleware3 start') return next().then((res) => { console.log("3",res) return 'middleware3 end' }) } const middlewares = [middleware1, middleware2, middleware3]function run (req, res) { const next = () => { const middleware = middlewares.shift() if (middleware) { // console.log("next",next) // 将middleware(req, res, next)包装为Promise对象 return Promise.resolve(middleware(req, res, next)) }else { return Promise.resolve("结束"); } } next() } run() // 模拟一次请求发起
有些中间件不止需要在业务处理前执行,还需要在业务处理后执行,比如统计时间的日志中间件。在方式一情况下,无法在next()
为异步操作时再将当前中间件的其他代码作为回调执行。因此可以将next()
方法的后续操作封装成一个Promise
对象,中间件内部就可以使用next.then()
形式完成业务处理结束后的回调。改写run()
方法如下:
const middleware1 = async (req, res, next) => { console.log('middleware1 start') let result = await next(); console.log("1",result) } const middleware2 = async (req, res, next) => { console.log('middleware2 start') let result = await next(); console.log("2",result) return 'middleware2 end'; } const middleware3 = async (req, res, next) => { console.log('middleware3 start') let result = await next(); console.log("3",result) return 'middleware3 end'; } const middlewares = [middleware1, middleware2, middleware3] function run (req, res) { const next = () => { const middleware = middlewares.shift() if (middleware) { // console.log("next",next) // 将middleware(req, res, next)包装为Promise对象 return Promise.resolve(middleware(req, res, next)) }else { return Promise.resolve("结束"); } } next() } run() // 模拟一次请求发起
中间件的调用方式需改写为:
function compose (middleware) { if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!') for (const fn of middleware) { if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!') } return function (context, next) { let index = -1 return dispatch(0) function dispatch (i) { // index会在next()方法调用后累加,防止next()方法重复调用 if (i <= index) return Promise.reject(new Error('next() called multiple times')) index = i let fn = middleware[i] if (i === middleware.length) fn = next if (!fn) return Promise.resolve() try { // 核心代码 // 包装next()方法返回值为Promise对象 return Promise.resolve(fn(context, dispatch.bind(null, i + 1))); } catch (err) { // 遇到异常中断后续中间件的调用 return Promise.reject(err) } } } }rrreee
结果:
async await 实现
以上描述了中间件机制中多个异步中间件的调用流程,实际中间件机制的实现还需要考虑异常处理、路由等。
在express
框架中,中间件的实现方式为方式一,并且全局中间件和内置路由中间件中根据请求路径定义的中间件共同作用,不过无法在业务处理结束后再调用当前中间件中的代码。koa2
框架中中间件的实现方式为方式二,将next()
方法返回值封装成一个Promise
,便于后续中间件的异步流程控制,实现了koa2
框架提出的洋葱圈模型,即每一层中间件相当于一个球面,当贯穿整个模型时,实际上每一个球面会穿透两次。
koa2
rrreeerrreee
rrreee
🎜🎜Ce qui précède décrit de nombreux des mécanismes middleware Concernant le processus d'appel du middleware asynchrone, la mise en œuvre réelle du mécanisme middleware doit également prendre en compte la gestion des exceptions, le routage, etc. 🎜🎜Dans le frameworkexpress
, le middleware est implémenté dans la méthode 1, et le middleware global et le middleware défini en fonction du chemin de requête dans le middleware de routage intégré fonctionnent ensemble, mais ils ne peuvent pas être utilisés une fois le traitement métier terminé, appelez ensuite le code dans le middleware actuel. La méthode d'implémentation du middleware dans le framework koa2
est la méthode deux. La valeur de retour de la méthode next()
est encapsulée dans une Promesse
pour faciliter. middleware ultérieur Le contrôle de processus asynchrone implémente le modèle de rondelles d'oignon proposé par le framework koa2
, c'est-à-dire que chaque couche de middleware est équivalente à une sphère. Lorsqu'elle pénètre dans tout le modèle, chaque sphère pénètre en fait deux fois. 🎜🎜🎜modèle de rondelle d'oignon middleware koa2🎜🎜koa2
Le mécanisme middleware du framework est très simple et élégant. Ici, nous apprendrons le code de base de la combinaison de plusieurs middlewares dans le framework. 🎜rrreee🎜adresse de la liste des middlewares koa : https://github.com/koajs/koa/wiki 🎜🎜Résumé🎜🎜Cet article présente principalement le concept de middleware, pourquoi le middleware est introduit et la mise en œuvre de base du mécanisme du middleware. Le mécanisme middleware permet aux applications Web d'avoir une bonne évolutivité et composabilité. 🎜
Lors de la mise en œuvre d'un middleware, un seul middleware doit être assez simple et avoir une seule responsabilité. Étant donné que chaque requête appellera le code lié au middleware, le code du middleware doit être efficace et peut mettre en cache les données obtenues à plusieurs reprises si nécessaire. Lorsque vous utilisez un middleware pour différentes routes, vous devez également considérer que différents middlewares s'appliquent à différentes routes.
【Apprentissage recommandé : "Tutoriel Nodejs"】
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!