日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Koa 中间件的执行

發布時間:2024/7/5 编程问答 201 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Koa 中间件的执行 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Node.js 中請求的處理

討論 Koa 中間件前,先看原生 Node.js 中是如何創建 server 和處理請求的。

node_server.js

const http = require("http"); const PORT = 3000;const server = http.createServer((req, res) => {res.end("hello world!"); });server.listen(PORT); console.log(`server started at http://localhost:${PORT}`);

Koa 中請求的處理

Koa 也是通過上面的 http.createServer 創建服務器處理請求的返回 res。 但在 Koa 的封裝體系下,其提供了十分好用的中間件系統,可對請求 req 及返回 res 進行便捷地處理。

koa/lib/application.js#L64

listen(...args) {debug('listen'); + const server = http.createServer(this.callback());return server.listen(...args);}

Koa 中的 hello world:

server.js

const Koa = require("koa"); const app = new Koa();app.use(async ctx => {ctx.body = "Hello World"; });app.listen(3000);

Koa 中,涉及到對請求返回處理都是通過中間件完成的,像上面為樣,返回頁面一個 Hello World 文本,也是調用 app.use 向 Application 對象注冊了個中間件來完成。

Koa 中間件編寫及使用

Koa 中中間件即一個處理請求的方法,通過調用 app.use(fn) 后,中間件 fn 被保存到了內部一個中間件數組中。

koa/lib/application.js#L105

use(fn) {if (typeof fn !== 'function') throw new TypeError('middleware must be a function!');if (isGeneratorFunction(fn)) {deprecate('Support for generators will be removed in v3. ' +'See the documentation for examples of how to convert old middleware ' +'https://github.com/koajs/koa/blob/master/docs/migration.md');fn = convert(fn);}debug('use %s', fn._name || fn.name || '-');this.middleware.push(fn);return this;}

通過上面的代碼可看到,注冊的中間件被壓入 Application 對象的 this.middleware 數組。這里有對傳入的方法進行判斷,區分是否為生成器([generator])方法,因為較早版本的 Koa 其中間件是通過生成器來實現的,后面有 async/await 語法后轉向了后者,所以更推薦使用后者,因此這里有廢棄生成器方式的提示。

因為中間件中需要進行的操作是不可控的,完全有可能涉及異步操作,比如從遠端獲取數據或從數據庫查詢數據后返回到 ctx.body,所以理論上中間件必需是異步函數。

比如實現計算一個請求耗時的中間件,以下分別是通過普通函數配合 Promise 以及使用 async/await 方式實現的版本:

來自官方 README 中使用 Promise 實現中間件的示例代碼

// Middleware normally takes two parameters (ctx, next), ctx is the context for one request, // next is a function that is invoked to execute the downstream middleware. It returns a Promise with a then function for running code after completion.app.use((ctx, next) => {const start = Date.now();return next().then(() => {const ms = Date.now() - start;console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);}); });

來自官方 README 中使用 async/await 實現中間件的示例代碼

app.use(async (ctx, next) => {const start = Date.now();await next();const ms = Date.now() - start;console.log(`${ctx.method} ${ctx.url} - ${ms}ms`); });

可以看到,一個中間件其簽名是 (ctx,next)=>Promise,其中 ctx 為請求上下文對象,而 next 是這樣一個函數,調用后將執行流程轉入下一個中間件,如果當前中間件中沒有調用 next,整個中間件的執行流程則會在這里終止,后續中間件不會得到執行。以下是一個測試。

server.js

app.use(async (ctx, next) => {console.log(1);next(); }); app.use(async (ctx, next) => {console.log(2); }); app.use(async (ctx, next) => {console.log(3);ctx.body = "Hello, world!"; });

執行后控制臺輸出:

$ node server.js 1 2

訪問頁面也不會看到 Hello, world! 因為設置響應的代碼 ctx.body = "Hello, world!"; 所在的中間件沒有被執行。

compose

下面來看當多次調用 app.use 注冊中間件后,這些中間件是如何被順次執行的。

中間件的執行是跟隨一次請求的。當一個請求來到后臺,中間件被順次執行,在各中間件中對請求 request 及 resposne 進行各種處理。

所以從 Koa 中處理請求的地方出發,找到中間件執行的源頭。

通過查看 lib/application.js 中相關代碼:

lib/application.js#L127

callback() { + const fn = compose(this.middleware);if (!this.listenerCount('error')) this.on('error', this.onerror);const handleRequest = (req, res) => {const ctx = this.createContext(req, res);return this.handleRequest(ctx, fn);};return handleRequest;}

可定位到存儲在 this.middleware 中的中間件數組會傳遞給 compose 方法來處理,處理后得到一個函數 fn,即這個 compose 方法處理后,將一組中間件函數處理成了一個函數,最終在 handleRequest 處被調用,開啟了中間件的執行流程。

lib/application.js#L151

handleRequest(ctx, fnMiddleware) {const res = ctx.res;res.statusCode = 404;const onerror = err => ctx.onerror(err);const handleResponse = () => respond(ctx);onFinished(res, onerror); + return fnMiddleware(ctx).then(handleResponse).catch(onerror);}

即 compose 的簽名長這樣:compose([a, b, c, ...]),它來自另一個單獨的倉庫 koajs/compose,其代碼也不復雜:

koajs/compose/index.js

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!");}/** * @param {Object} context * @return {Promise} * @api public */return function(context, next) {// last called middleware #let index = -1;return dispatch(0);function dispatch(i) {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 {return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));} catch (err) {return Promise.reject(err);}}}; }

這個方法只做了兩件事,

  • 定義了一個 dispatch 方法,
  • 然后調用它 dispatch(0)

這里中間件從數組中取出并順次執行的邏輯便在 dispatch 函數中。

整體方法體中維護了一個索引 index 其初始值為 -1,后面每調用一次 dispatch 會加 1。當執行 dispatch(0) 時,從中間件數組 middleware 中取出第 0 個中間件并執行,同時將 dispatch(i+1) 作為 next 傳遞到下一次執行。

let fn = middleware[i]; return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));

所以這里就能理解,為什么中間件中必需調用 next,否則后續中間件不會執行。

這樣一直進行下去直到所有中間件執行完畢,此時 i === middleware.length,最后一個中間件已經執行完畢,next 是沒有值的,所以直接 resolve 掉結束中間件執行流程。

if (i === middleware.length) fn = next; if (!fn) return Promise.resolve();

回到中間件被喚起的地方:

lib/application.js

fnMiddleware(ctx).then(handleResponse).catch(onerror);

中間件完成后,流程到了 handleResponse。

總結

從中間件執行流程可知道:

  • 中間件之間存在順序的問題,先注冊的先執行。
  • 中間件中需要調用 next 以保證后續中間件的執行。當然,如果你的中間件會根據一些情況阻止掉后續中間件的執行,那可以不調用 next,比如一個對請求進行權限校驗的中間件可以這么寫:
app.use(async (ctx, next) => {// 獲取權限數據相關的操作...if (valid) {await next();} else {ctx.throw(403, "沒有權限!");} });

相關資源

  • Koa documentation
  • Node.js Documentation - HTTP Class: http.Server
  • MDN - function*
  • koajs/compose

轉載于:https://www.cnblogs.com/Wayou/p/koa_middleware.html

總結

以上是生活随笔為你收集整理的Koa 中间件的执行的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 手机在线成人av | 久操精品 | 亚洲精品国产精品国自产观看浪潮 | 波多野结衣在线看 | 日吊视频| 激情第四色| 国产精品一区免费观看 | 蜜臀av一区二区三区有限公司 | 国产无精乱码一区二区三区 | 色婷婷av一区二区三区在线观看 | 大肉大捧一进一出视频 | 亚洲综合色在线 | www插插插无码免费视频网站 | 日韩人妻无码精品综合区 | 亚洲精品无码不卡在线播he | 午夜精品久久久久久久99热浪潮 | 国产大片一区 | 国模吧一区二区三区 | 熊猫成人网 | 69视频网站| 亚洲视频在线视频 | 亚洲综合精品国产一区二区三区 | 狠狠干2024| 老司机午夜剧场 | 一级片中文字幕 | 成人天堂噜噜噜 | 91激情网| 免费级毛片 | 国产精品白丝喷水在线观看 | 误杀1电影免费观看高清完整版 | 亚洲天堂成人av | 欧美日韩三级在线观看 | 国产人人爱 | www.色com | 久久久综合久久 | 在线播放的av | 天天干天天插天天操 | 欧美日韩精品一二三区 | 美女的胸给男人玩视频 | 激情欧美网站 | 国产福利在线视频观看 | 中文字幕有码在线播放 | 国产精品免费一区二区三区 | 亚洲色图国产精品 | 日韩深夜在线 | 九色91av| 六月婷婷久久 | 少妇大叫太粗太大爽一区二区 | 99综合| 污网站免费在线 | 国产在线国偷精品免费看 | 欧美午夜精品一区二区三区电影 | 亚洲精品777 | 樱桃视频污污 | 无遮挡黄色| 黄色免费在线播放 | 激情欧美一区二区 | 日韩精品一区二区三区电影 | 老熟妇精品一区二区三区 | 182tv午夜 | 伊人网免费视频 | 人人爱操 | 国内性视频 | 国内久久| 亚洲三级在线 | 中文字幕蜜臀 | 欧美日韩在线播放 | 喷水了…太爽了高h | 亚洲成a人片在线 | 超碰av人人| 黄网免费在线观看 | 成人网在线免费观看 | 色葡萄影院 | 香蕉网在线 | 欧美日韩影院 | 麻豆传媒网址 | 伊人日日夜夜 | 国产三级视频 | 亚洲av无码一区二区三区人妖 | 色666| 伊人avav| 人人妻人人爽人人澡人人精品 | 超碰狠狠操 | 日本中文字幕一区 | 久草免费看| av一卡| 四虎新网站 | 婷婷激情影院 | 一区二区三区成人 | 免费av大全 | 五月天激情综合网 | 国产手机在线播放 | 韩国在线不卡 | 91se在线| 午夜影院福利 | av网页在线 | 午夜视频一区 | 国产精品一区二区无码免费看片 | 一区二区三区不卡在线 |