1. 程式人生 > >深入理解 Koa 框架中介軟體原理

深入理解 Koa 框架中介軟體原理

Node 主要用在開發 Web 應用,koa 是目前 node 裡最流行的 web 框架。

在 Node 開啟一個 http 服務簡直易如反掌,官網 demo。

const http = require("http");
 
const server = http.createServer((req, res) => {
 res.statusCode = 200;
 res.setHeader("Content-Type", "text/plain");
 res.end("Hello World\n");
});
 
const hostname = "127.0.0.1";
const port = 3000;
server.listen(port, hostname, () => {
 console.log(`Server running at http://${hostname}:${port}/`);
});
//前端全棧學習交流圈:866109386
//面向1-3經驗年前端開發人員
//幫助突破技術瓶頸,提升思維能力
  • 引入 http 模組, http 的 createServer 方法建立了一個 http.Server 的例項。
  • server 監聽 3000 埠。
  • 我們傳入到 createServer 裡的函式實際是監聽 request 事件的回撥,每當請求進來,監聽函式就會執行。
  • request 事件的監聽函式,其函式接受兩個引數,分別是 req 和 res 。其中 req 是一個可讀流, res 是一個可寫流。我們通過 req 獲取 http 請求的所有資訊,同時將資料寫入到 res 來對該請求作出響應。

koa 應用

koa 如何建立一個 server, 直接上個官網的例子

const Koa = require("koa");
const app = new Koa();
 
// x-response-time
 
app.use(async (ctx, next) => {
 const start = Date.now();
 await next();
 const ms = Date.now() - start;
 ctx.set("X-Response-Time", `${ms}ms`);
});
 
// logger
 
app.use(async (ctx, next) => {
 const start = Date.now();
 await next();
 const ms = Date.now() - start;
 console.log(`${ctx.method} ${ctx.url} - ${ms}`);
});
 
// response
 
app.use(async ctx => {
 ctx.body = "Hello World";
});
 
app.listen(3000);
//前端全棧學習交流圈:866109386
//面向1-3經驗年前端開發人員
//幫助突破技術瓶頸,提升思維能力

中介軟體概念在程式設計中使用廣泛, 不管是前端還是後端, 在實際程式設計中或者框架設計都有使用到這種實用的模型。

基本上,Koa 所有的功能都是通過中介軟體實現的。

每個中介軟體預設接受兩個引數,第一個引數是 Context 物件,第二個引數是 next 函式。只要呼叫 next 函式,就可以把執行權轉交給下一個中介軟體。

如果中介軟體內部沒有呼叫 next 函式,那麼執行權就不會傳遞下去。

多箇中間件會形成一個棧結構(middle stack),以“先進後出”(first-in-last-out)的順序執行。整個過程就像,先是入棧,然後出棧的操作。

上面程式碼的執行順序是:

請求 ==> x-response-time 中介軟體 ==> logger 中介軟體 ==> response中介軟體 ==> logger 中介軟體 ==> response-time 中介軟體 ==> 響應

理解 Koa 的中介軟體機制(原始碼分析)

閱讀原始碼,化繁為簡,我們看看 koa 的中介軟體系統是如何實現的。

function compose(middleware) {
 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);
   }
  }
 };
}
//前端全棧學習交流圈:866109386
//面向1-3經驗年前端開發人員
//幫助突破技術瓶頸,提升思維能力

我試圖去簡化一下這個方法,但方法本身已經足夠簡潔。

程式碼很簡潔。

通過 next()傳遞 實現中介軟體呼叫, 結合 Promise 採用 遞迴呼叫 的通知機制。

看圖 這種形式的控制流讓整個 Koa 框架中介軟體的訪問呈現出 自上而下的中介軟體流 + 自下而上的 response 資料流 的形式。

Koa 本身做的工作僅僅是定製了中介軟體的編寫規範,而不內建任何中介軟體。一個 web request 會通過 Koa 的中介軟體棧,來動態完成 response 的處理。

koa 在中介軟體語法上面採用了 async + await 語法來生成 Promise 形式的程式控制流。