Koa學(xué)習筆記

開啟服務(wù)器

const http = require('http');
const Koa = require('koa');

const app = new Koa();
app.listen(3000);//相當于 http.createServer(app.callback()).listen(3000);

中間件

Koa 的最大特色,也是最重要的一個設(shè)計,就是中間件(middleware)

  1. 中間件的概念
// Logger (打印日志)功能的實現(xiàn)
const logger = (ctx, next) => {
  console.log(`${Date.now()} ${ctx.request.method} ${ctx.request.url}`);
  next();
}
app.use(logger);

代碼中的logger函數(shù)就叫做"中間件"(middleware),因為它處在 HTTP Request 和 HTTP Response 中間,用來實現(xiàn)某種中間功能。app.use()用來加載中間件。

基本上,Koa 所有的功能都是通過中間件實現(xiàn)的,前面例子里面的main也是中間件。每個中間件默認接受兩個參數(shù),第一個參數(shù)是 Context 對象,第二個參數(shù)是next函數(shù)。只要調(diào)用next函數(shù),就可以把執(zhí)行權(quán)轉(zhuǎn)交給下一個中間件。

  1. 中間件棧

多個中間件會形成一個棧結(jié)構(gòu)(middle stack),以"先進后出"(first-in-last-out)的順序執(zhí)行。

1. 最外層的中間件首先執(zhí)行。
2. 調(diào)用next函數(shù),把執(zhí)行權(quán)交給下一個中間件。
3. ...
4. 最內(nèi)層的中間件最后執(zhí)行。
5. 執(zhí)行結(jié)束后,把執(zhí)行權(quán)交回上一層的中間件。
6. ...
7. 最外層的中間件收回執(zhí)行權(quán)之后,執(zhí)行next函數(shù)后面的代碼。
const one = (ctx, next) => {
  console.log('>> one');
  next();
  console.log('<< one');
}

const two = (ctx, next) => {
  console.log('>> two');
  next(); 
  console.log('<< two');
}

const three = (ctx, next) => {
  console.log('>> three');
  next();
  console.log('<< three');
}

app.use(one);
app.use(two);
app.use(three);

輸出:

>> one
>> two
>> three
<< three
<< two
<< one

如果中間件內(nèi)部沒有調(diào)用next函數(shù),那么執(zhí)行權(quán)就不會傳遞下去。將two函數(shù)里面next()這一行注釋掉再執(zhí)行,會輸出:

>> one
>> two
<< two
<< one
  1. 中間件的合成

koa-compose模塊可以將多個中間件合成為一個。

const compose = require('koa-compose');

const logger = (ctx, next) => {
  console.log(`${Date.now()} ${ctx.request.method} ${ctx.request.url}`);
  next();
}

const main = ctx => {
  ctx.response.body = 'Hello World';
};

const middlewares = compose([logger, main]);
app.use(middlewares);

錯誤處理

  1. 網(wǎng)頁錯誤
    如果代碼運行過程中發(fā)生錯誤,我們需要把錯誤信息返回給用戶。HTTP 協(xié)定約定這時要返回500狀態(tài)碼。Koa 提供了ctx.throw()方法,用來拋出錯誤,ctx.throw(500)就是拋出500錯誤?;蛘邔?code>ctx.response.status設(shè)置成500,就相當于ctx.throw(500),返回500錯誤。但是如果要在try ... catch中捕獲異常,就要用ctx.throw(500),拋出異常。
const main = ctx => {
  ctx.throw(500);
};
// 相當于
const main = ctx => {
  ctx.response.status = 500;
  ctx.response.body = 'Internal Server Error';
};

訪問會看到一個500錯誤頁"Internal Server Error"。

  1. 處理錯誤的中間件
    為了方便處理錯誤,最好使用try...catch將其捕獲。但是,為每個中間件都寫try...catch太麻煩,我們可以讓最外層的中間件,負責所有中間件的錯誤處理。
const handler = async (ctx, next) => {
  try {
    await next();
  } catch (err) {
    ctx.response.status = err.statusCode || err.status || 500;
    ctx.response.body = {
      message: err.message
    };
  }
};

const main = ctx => {
  ctx.throw(500);
};

app.use(handler);
app.use(main);

看到一個500頁,里面有報錯提示 {"message":"Internal Server Error"}

  1. error 事件的監(jiān)聽
    運行過程中一旦出錯,Koa 會觸發(fā)一個error事件。監(jiān)聽這個事件,也可以處理錯誤。
const main = ctx => {
  ctx.throw(500);
};

app.on('error', (err, ctx) => {
  console.error('server error', err);
});
  1. 釋放 error 事件
    需要注意的是,如果錯誤被try...catch捕獲,就不會觸發(fā)error事件。這時,必須調(diào)用ctx.app.emit(),手動釋放error事件,才能讓監(jiān)聽函數(shù)生效。
const handler = async (ctx, next) => {
  try {
    await next();
  } catch (err) {
    ctx.response.status = err.statusCode || err.status || 500;
    ctx.response.type = 'html';
    ctx.response.body = '<p>Something wrong, please contact administrator.</p>';
    ctx.app.emit('error', err, ctx);
  }
};

const main = ctx => {
  // 需要用throw方法拋出錯誤
  ctx.throw(500);
};

app.on('error', function(err) {
  console.log('logging error ', err.message);
  console.log(err);
});

上面代碼中,main函數(shù)拋出錯誤,被handler函數(shù)捕獲。catch代碼塊里面使用ctx.app.emit()手動釋放error事件,才能讓監(jiān)聽函數(shù)監(jiān)聽到。

參考

  1. Koa 框架教程
  2. Koa
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、基本用法 1.1 架設(shè) HTTP 服務(wù) // demos/01.jsconst Koa = require('...
    majun00閱讀 1,538評論 0 5
  • 1.簡書 koa是由Express原班人馬打造,致力于成為一個更小、更富有表現(xiàn)力、更健壯的Web框架。使用koa編...
    不去解釋閱讀 2,802評論 0 11
  • Koa的執(zhí)行過程 背景:JavaScript為了實現(xiàn)異步編程,傳統(tǒng)的方式有回調(diào)函數(shù)、事件監(jiān)聽等。所謂回調(diào)函數(shù),就是...
    蘇星河閱讀 435評論 0 1
  • 陸陸續(xù)續(xù)用了koa和co也算差不多用了大半年了,大部分的場景都是在服務(wù)端使用koa來作為restful服務(wù)器用,使...
    Sunil閱讀 1,680評論 0 3
  • Koa 學(xué)習 歷史 Express Express是第一代最流行的web框架,它對Node.js的http進行了封...
    Junting閱讀 2,934評論 0 0

友情鏈接更多精彩內(nèi)容