摘要 - 廖雪峰JavaScript教程
創(chuàng)建一個koa2工程
首先,我們創(chuàng)建一個test目錄,并在目錄里面創(chuàng)建一個koa.js文件,輸入以下代碼:
// 導入的是koa2,不是koa1,koa2是一個class類,所以大寫。
const Koa = require('koa')
// 創(chuàng)建一個web app 實例
const app = new Koa()
// 對于任何請求,都執(zhí)行該回調(diào)函數(shù)
app.use(async (ctx, next) => {
await next()
ctx.response.type = 'text/html'
ctx.response.body = '<h1> Hello Koa2 </h1>'
})
// 監(jiān)聽9000端口
app.listen(9000, () => {
console.log('Server is running and the port is 9000 ')
})
其中,參數(shù)ctx是koa傳入的封裝了response和resquest的變量,next是koa要處理的下一個異步函數(shù)。
上面的異步函數(shù)中,我們首先用await next( )處理下一個異步函數(shù),然后設(shè)置Content-Type和內(nèi)容。
由async標記的函數(shù)稱為異步函數(shù),在異步函數(shù)中,可以用await調(diào)用另一個異步函數(shù),這兩個關(guān)鍵字在ES7中引入。
<font color=red>注意:</font>要是想運行上面的代碼,請使用最新的node7以后的版本,因為低版本的node不支持async和await關(guān)鍵,或者你可以babel進行轉(zhuǎn)成es5進行運行。
koa middleware
讓我們在仔細看下koa的執(zhí)行邏輯。核心代碼是:
app.use(async (ctx, next) => {
await next()
ctx.response.type = 'text/html'
ctx.response.body = '<h1> Hello Koa2 </h1>'
})
每收到一個http請求,koa就會調(diào)用通過app.use()注冊的異步函數(shù),并傳入ctx和next參數(shù)。
我們可以對ctx操作,并設(shè)置返回內(nèi)容。但是為什么要調(diào)用await next()?
原因是koa把很多async函數(shù)組成一個處理鏈,每個async函數(shù)都可以做一些自己的事情,然后用await next()來調(diào)用下一個async函數(shù)。我們把每個async函數(shù)稱為middleware,這些middleware可以組合起來,完成很多有用的功能。
例如,可以用以下3個middleware組成處理鏈,依次打印日志,記錄處理時間,輸出HTML:
app.use(async (ctx, next) => {
console.log(`${ctx.request.method} ${ctx.request.url}`); // 打印URL
await next(); // 調(diào)用下一個middleware
});
app.use(async (ctx, next) => {
const start = new Date().getTime(); // 當前時間
await next(); // 調(diào)用下一個middleware
const ms = new Date().getTime() - start; // 耗費時間
console.log(`Time: ${ms}ms`); // 打印耗費時間
});
app.use(async (ctx, next) => {
await next();
ctx.response.type = 'text/html';
ctx.response.body = '<h1>Hello, koa2!</h1>';
});
middleware的順序很重要,也就是調(diào)用app.use()的順序決定了middleware的順序。
此外,如果一個middleware沒有調(diào)用await next(),會怎么辦?答案是后續(xù)的middleware將不再執(zhí)行了。這種情況也很常見,例如,一個檢測用戶權(quán)限的middleware可以決定是否繼續(xù)處理請求,還是直接返回403錯誤:
app.use(async (ctx, next) => {
if (await checkUserPermission(ctx)) {
await next();
} else {
ctx.response.status = 403;
}
});
理解了middleware,我們就基本會用koa了!
最后注意ctx對象有一些簡寫的方法,例如ctx.url相當于ctx.request.url,ctx.type相當于ctx.response.type。