Heim > Artikel > Web-Frontend > Was bedeutet Middleware in NodeJS?
In NodeJS bezieht sich Middleware hauptsächlich auf die Methode, die die detaillierte Verarbeitung aller HTTP-Anfragen kapselt. Es handelt sich um die Verarbeitungsmethode von der Einleitung der HTTP-Anfrage bis zum Ende der Antwort. Das Verhalten von Middleware ähnelt dem Funktionsprinzip von Filtern in Java, das darin besteht, den Filter damit zu befassen, bevor er in eine bestimmte Geschäftsverarbeitung eintritt.
Die Betriebsumgebung dieses Tutorials: Windows7-System, NodeJS-Version 12.19.0, Dell G3-Computer.
In NodeJS bezieht sich Middleware hauptsächlich auf die Methode, die alle HTTP-Anforderungsdetails kapselt. Eine HTTP-Anfrage erfordert normalerweise viel Arbeit, wie Protokollierung, IP-Filterung, Abfragezeichenfolgen, Analyse des Anforderungstexts, Cookie-Verarbeitung, Berechtigungsüberprüfung, Parameterüberprüfung, Ausnahmebehandlung usw. Bei Webanwendungen ist dies jedoch nicht der Fall ausgesetzt so viel Detailverarbeitung, daher wird Middleware eingeführt, um die Details zwischen dieser Infrastruktur und der Geschäftslogik zu vereinfachen und zu isolieren, sodass sich Entwickler auf die Geschäftsentwicklung konzentrieren können, um den Zweck der Verbesserung der Entwicklungseffizienz zu erreichen.
Das Verhalten von Middleware ähnelt dem Funktionsprinzip von Filtern in Java, das darin besteht, den Filter damit zu befassen, bevor er in eine bestimmte Geschäftsverarbeitung eintritt. Das Arbeitsmodell ist in der folgenden Abbildung dargestellt.
const middleware = (req, res, next) => { // TODO next() }
Methode 1
Definieren Sie drei einfache Middleware wie folgt: 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() // 模拟一次请求发起
Führen Sie den obigen Code aus. Sie können die folgenden Ergebnisse sehen: middleware1 start
middleware2 start
middleware3 start
Wenn es einen asynchronen Vorgang in der Middleware gibt, muss er bei enden das Ende des asynchronen Operationsprozesses Rufen Sie dann die Methode next()
auf, andernfalls kann die Middleware nicht nacheinander ausgeführt werden. Schreiben Sie Middleware2 Middleware neu:
const middleware2 = (req, res, next) => { console.log('middleware2 start') new Promise(resolve => { setTimeout(() => resolve(), 1000) }).then(() => { next() }) }
Das Ausführungsergebnis ist das gleiche wie zuvor, aber Middleware3 wird ausgeführt, nachdem Middleware2 asynchron abgeschlossen wurde.
middleware1 start middleware2 start middleware3 start
Einige Middleware muss nicht nur vor der Geschäftsverarbeitung ausgeführt werden, sondern auch nach der Geschäftsverarbeitung, z. B. Protokoll-Middleware für statistische Zeit. Bei Methode 1 können andere Codes der aktuellen Middleware nicht als Callbacks ausgeführt werden, wenn next()
eine asynchrone Operation ist. Daher können die nachfolgenden Operationen der next()
-Methode in ein Promise
-Objekt gekapselt werden und die Middleware kann mit next.then()-Formular. Rückruf nach Abschluss der Geschäftsabwicklung. Schreiben Sie die <code>run()
-Methode wie folgt um:
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() }
Die aufrufende Methode der Middleware muss wie folgt umgeschrieben werden: 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
🎜🎜Das Obige beschreibt mehrere Aspekte des Middleware-Mechanismus Was den Aufrufprozess der asynchronen Middleware betrifft, müssen bei der tatsächlichen Implementierung des Middleware-Mechanismus auch Ausnahmebehandlung, Routing usw. berücksichtigt werden. 🎜🎜Imexpress
-Framework wird die Middleware in Methode 1 implementiert, und die globale Middleware und die gemäß dem Anforderungspfad in der integrierten Routing-Middleware definierte Middleware arbeiten zusammen, können jedoch nicht verwendet werden Rufen Sie nach Abschluss der Geschäftsverarbeitung den Code in der aktuellen Middleware auf. Die Implementierungsmethode der Middleware im koa2
-Framework ist Methode zwei. Der Rückgabewert der next()
-Methode ist zur Vereinfachung in ein Promise
gekapselt Die nachfolgende asynchrone Prozesssteuerung der Middleware implementiert das vom koa2
-Framework vorgeschlagene Zwiebelringmodell, d. h. jede Middlewareschicht entspricht einer Kugel. Wenn sie das gesamte Modell durchdringt, dringt jede Kugel tatsächlich zweimal ein. 🎜🎜🎜koa2 Middleware-Zwiebelringmodell🎜🎜koa2
Der Middleware-Mechanismus des Frameworks ist sehr einfach und elegant. Hier lernen wir den Kerncode für die Kombination mehrerer Middlewares im Framework. 🎜rrreee🎜Adresse der Koa-Middleware-Liste: https://github.com/koajs/koa/wiki 🎜🎜Zusammenfassung🎜🎜In diesem Artikel wird hauptsächlich das Konzept der Middleware vorgestellt, warum Middleware eingeführt wird und die Kernimplementierung des Middleware-Mechanismus. Der Middleware-Mechanismus sorgt dafür, dass Webanwendungen eine gute Skalierbarkeit und Zusammensetzbarkeit aufweisen. 🎜
Bei der Implementierung von Middleware sollte eine einzelne Middleware einfach genug sein und eine einzige Verantwortung haben. Da jede Anfrage den Middleware-bezogenen Code aufruft, sollte der Middleware-Code effizient sein und bei Bedarf wiederholt abgerufene Daten zwischenspeichern können. Wenn Sie Middleware für unterschiedliche Routen verwenden, sollten Sie auch berücksichtigen, dass unterschiedliche Middleware für unterschiedliche Routen gilt.
【Empfohlenes Lernen: „nodejs-Tutorial“】
Das obige ist der detaillierte Inhalt vonWas bedeutet Middleware in NodeJS?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!