関連する推奨事項: 「nodejs チュートリアル 」
ミドルウェアと言えば、多くの開発者は Koa.js を思い浮かべるでしょう。そして、そのミドルウェア設計は間違いなく優れています。フロントエンドミドルウェアの考え方の代表的なものの一つです。
最近コンテンツのこの部分を見直したところ、その素晴らしさについて読者の皆さんと話したいと思わずにはいられませんでした。
Koa は非常に使いやすく、Express と比べて「完璧なミドルウェア」設計のため、機能が非常にシンプルに見えます。作者はプロジェクトでこれを次のように使用しました:
const Koa=require('koa') const app=new Koa() const Router=require('koa-router') const router=new Router() const cors=require('koa2-cors') const koaBody=require('koa-body') const ENV='test-mpin2' app.use(cors({ origin:['http://localhost:9528'], // 也可以写为:['*'] credentials:true })) app.use(koaBody({ multipart:true })) app.use(async(ctx,next)=>{ console.log('访问全局中间件') ctx.state.env=ENV // 全局缓存 await next() }) const playlist=require('./controller/playlist.js') router.use('/playlist',playlist.routes()) const blog=require('./controller/blog.js') router.use('/blog',blog.routes()) app.use(router.routes()).use(router.allowedMethods()) app.listen(3000,()=>{ console.log('服务已开启') })
これはルーティング ルーターを抽出して別のミドルウェアとして使用し、アプリはグローバル処理のみを担当します。別の例:
// 最外层中间件,可以用于兜底 Koa 全局错误 app.use(async (ctx, next) => { try { // 执行下一个中间件 await next(); } catch (error) { console.log(`[koa error]: ${error.message}`) } }); // 第二层中间件,可以用于日志记录 app.use(async (ctx, next) => { const { req } = ctx; console.log(`req is ${JSON.stringify(req)}`); await next(); console.log(`res is ${JSON.stringify(ctx.res)}`); });
Koa を実装するだけです。
上記のコードに示すように、Koa インスタンスを確認し、use メソッドを通じてミドルウェアを登録および連結します。ソース コードの単純な実装は次のように表現できます:
use(fn) { this.middleware.push(fn); return this; }
ミドルウェアを this.middleware
に格納します。この配列では、ミドルウェアはどのように実行されるのでしょうか?以下のソース コードを参照してください。
// 通过 createServer 方法启动一个 Node.js 服务 listen(...args) { const server = http.createServer(this.callback()); server.listen(...args); }
Koa フレームワークは、http モジュールの createServer
メソッドを通じて Node.js サービスを作成し、this.callback()# に渡します。 ## メソッド、コールバック ソース コード 簡単な実装は次のとおりです。
callback(){ const fn=compose(this.middlewareList) return (req,res)=>{ const ctx=createContext(req,res) return this.handleRequest(ctx,fn) } } handleRequest(ctx, fn) { const onerror = err => ctx.onerror(err); // 将 ctx 对象传递给中间件函数 fn return fn(ctx).catch(onerror); }
メソッドが最初に呼び出され、メソッドが完了します :
次に、
// 组合中间件 // 和express中的next函数意义一样 function compose(middlewareList){ // return function意思是返回一个函数 return function(ctx,next){ // 各种中间件调用的逻辑 function dispatch(i){ const fn=middlewareList[i] || next if(fn){ try{ // koa中都是async,其返回的是一个promise(对象) return Promise.resolve(fn(ctx,function next(){ return dispatch(i+1) })) }catch(err){ return Promise.reject(err) } }else{ return Promise.resolve() } } return dispatch(0) } }
async function middleware1() { //... await (async function middleware2() { //... await (async function middleware3() { //... }); //... }); //... }
Koa のミドルウェア メカニズムは、コミュニティによってオニオン モデルとして鮮やかに要約されています;
dispatch(n) は、n 番目のミドルウェアの実行に対応します。使用中に、n 番目のミドルウェアを「挿入」して、await next() を通じて次のミドルウェアを実行できます。同時に、最後のミドルウェアの実行が完了した後も、実行を再開することができます。つまり、オニオン モデルを通じて、await next() は、世界中に実行可能なミドルウェアがなくなり、スタックの実行が完了するまで後続のミドルウェアの呼び出しを制御し、最後に次に実行する最初のミドルウェアへの「元のパスに戻ります」。 。この方法には、特に、非常に使いやすくする必要があるロギングやエラー処理などのグローバル関数の場合に利点があります。
ソース コードの上記の部分を記述した後、es6 を使用してそれを組み合わせることができます:申し訳ありませんが、これについては Node のソース コードで詳しく調べる必要があります...使用方法は他の方法と同じではありません. 連動していますが、どのように実行されますか? createServer実行後、チャネルを確立してlisten機能を実装するのと同じでしょうか?// myKoa.js文件 const http=require('http') function compose(){} //见上 class LikeKoa2{ constructor() { this.middlewareList=[] } use(){} //见上 // 把所有的req,res属性、事件都交给ctx(这里只是简写) createContext(req,res){ const ctx={ req, res } // 比如 ctx.query=req,query return ctx } handleRequest(){} //见上 callback(){} //见上 listen(){} //见上 } // koa和express的不同之一: // express在调用时直接调用函数:const app=express();所以暴露出去new过的对象——具体见下面链接中代码 // 但是koa调用时以类的方式:const app=new Koa();所以直接暴露出去 module.exports=LikeKoa2ログイン後にコピー
Koa と比較し、Express の原理について話します
Node.js フレームワークといえば、Express を忘れてはなりません。Koa とは異なり、ルーティング、静的サーバー、テンプレート エンジンなどの機能を継承しています。Koa に比べてはるかに「肥大化」していますが、見た目はフレームワークに似ています。コアよりも。 Express のソース コードを調べて、作成者はその動作メカニズムを簡単に要約しました。
app.use メソッドを通じてミドルウェアを登録します。
ミドルウェアは、現在のルートとハンドル メソッドに一致する通常の情報を含む Layer オブジェクトとして理解できます。
すべてのミドルウェア (レイヤー オブジェクト) は、スタック配列を使用して保存されます。
リクエストが来ると、reqからリクエストのパスを取得し、そのパスに従ってスタックから一致するLayerを探します。具体的なマッチング処理は#によって行われます。 ##router.handle
関数が完了します。router.handle
next()
方法通过闭包维持了对于 Stack Index 游标的引用,当调用next()
方法时,就会从下一个中间件开始查找;layer.handle_request
方法,layer.handle_request
方法中会调用next()方法 ,实现中间件的执行。通过上述内容,我们可以看到,Express 其实是通过 next()
方法维护了遍历中间件列表的 Index 游标,中间件每次调用next()
方法时,会通过增加 Index 游标的方式找到下一个中间件并执行。它的功能就像这样:
((req, res) => { console.log('第一个中间件'); ((req, res) => { console.log('第二个中间件'); (async(req, res) => { console.log('第三个中间件'); await sleep(2000) res.status(200).send('hello') })(req, res) console.log('第二个中间件调用结束'); })(req, res) console.log('第一个中间件调用结束') })(req, res)
如上代码,Express 中间件设计并不是一个洋葱模型,它是基于回调实现的线形模型,不利于组合,不利于互操,在设计上并不像 Koa 一样简单。而且业务代码有一定程度的侵扰,甚至会造成不同中间件间的耦合。
express的简单实现笔者已上传至腾讯微云,需要者可自行查看&下载:express的简单实现
更多编程相关知识,请访问:编程视频!!
以上がNodejs ミドルウェア Koa と Express を比較するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。