聊聊 koa 中介軟體

言sir發表於2018-07-31

前言

koa是基於Node.js平臺的下一代web開發框架,它體積小,擴充套件性強,給人一種乾淨利落的程式設計方式,且由express原班人馬打造,國內很多網際網路公司都在使用,因此有必要學習總結下。

初出茅廬,來個hello word

  • 按照慣例,先來個demo 輸出hello world
let Koa = require('koa'); //引入koa
let app = new Koa();    //宣告一個例項app
app.use(async (ctx,next)=>{   //  對於任何請求,app將呼叫該非同步函式處理請求:
    ctx.body = "hello"
});
app.listen("3000");  //監聽埠
複製程式碼
  • 其中引數ctx是由koa傳入的封裝了request和response的變數,我們可以通過它訪問request和response。
  • next是koa傳入的將要處理的下一個非同步函式。
  • 由async標記的函式稱為非同步函式,在非同步函式中,可以用await呼叫另一個非同步函式,這個非同步函式必須返回一個promise,上篇文章寫過promise用法和實現原理,不瞭解可以先去看看。這兩個關鍵字將在ES7中引入。

聊聊 koa 中介軟體

簡捷的5行程式碼,幫我們開啟了3000埠的服務

深入理解Koa中介軟體之洋蔥模型

學習Koa重點在於理解中介軟體實現原理,對後續引用第三方庫中介軟體時候有更好了解。我們單獨講講

  • 先來段測試程式碼
let Koa = require('koa');
let app = new Koa();
app.use(async (ctx,next)=>{
    console.log(1);
   await next();
    console.log(2);
});
app.use(async (ctx,next)=>{
    console.log(3);
   await next();
    console.log(4);
});
app.listen("3000");
複製程式碼

你可能對執行的結果會說 1234,其實不然,我們先來看下輸出結果

聊聊 koa 中介軟體

聊聊 koa 中介軟體

一臉懵逼1342,這是什麼順序,這就是我們要說的洋蔥模型

  • 中介軟體的執行很像一個洋蔥,但並不是一層一層的執行,而是以next為分界,先執行本層中next以前的部分,當下一層中介軟體執行完後,再執行本層next以後的部分。
  • 一個洋蔥結構,從上往下一層一層進來,再從下往上一層一層回去,是不是有點感覺了。

聊聊 koa 中介軟體

1、koa-router中介軟體

koa-router基礎寫法
  • 為了講的詳細全面,把路由分為及部分來講解,先來看最基本的路由怎麼寫
let Koa = require('koa');
let app = new Koa();
let Router = require('koa-router');
let router = new Router();
router.get('/',async (ctx,next)=>{
    ctx.body = 'hello people';
    await next()
});
router.get('/list',async (ctx,next)=>{
    ctx.body = 'list';
});
app.use(router.routes()); // 掛載
app.use(router.allowedMethods());//當請求資料的方法與設定的方法不一致,會報錯。比如預設get請求獲取,用post發請求會報錯
app.listen(3000);
複製程式碼
koa-router中巢狀路由寫法

假如我們想為單個頁面設定層級,/home是我們首頁,再次基礎上有/home/list 首頁列表頁 /home/todo 首頁todo頁。這時我們就需要用到巢狀路由,看看怎麼用

const Koa = require('koa');
const app = new Koa();
const Router = require('koa-router');
//home的路由
let home = new Router();
home.get('/list',async(ctx)=>{
    ctx.body="Home list";
}).get('/todo',async(ctx)=>{
    ctx.body ='Home ToDo';
});
//page的路由
let page = new Router();
page.get('/list',async(ctx)=>{
    ctx.body="Page list";
}).get('/todo',async(ctx)=>{
    ctx.body ='Page todo';
});
//裝載所有子路由
let router = new Router();
router.use('/home',home.routes(),home.allowedMethods());
router.use('/page',page.routes(),page.allowedMethods());
//載入路由中介軟體
app.use(router.routes()).use(router.allowedMethods());
app.listen(3000);

複製程式碼

這樣一來就實現巢狀路由的寫法

聊聊 koa 中介軟體

koa-router引數的傳遞
  • 1、通過/arcicle/id/name傳參
let Koa = require('koa');
let app = new Koa();
let Router = require('koa-router');
let router = new Router();
//實現  /arcicle/id/name形式的傳參
router.get('/acticle/:id/:name',(ctx,next)=>{
    ctx.body = ctx.params.id +"-"+ ctx.params.name;
});
app.use(router.routes());
app.listen(3000);
複製程式碼

測試下,學過vue應該比較熟悉

聊聊 koa 中介軟體

  • 2、通過/arcicle?id=1&name=cgp傳參
const Koa = require('koa');
const Router = require('koa-router');
const app = new Koa();
const router = new Router();
router.get('/article', function (ctx, next) {
    ctx.body=ctx.query; //query方法實現json形式
});
app.use(router.routes())
app.listen(3000,()=>{
    console.log('starting at port 3000');
});
複製程式碼

聊聊 koa 中介軟體

2、koa-bodyparse()中介軟體

  • 用來解析請求體的中介軟體,比如獲取post提交的表單資料,通過koa-bodyparse解析後就能獲取到資料。看demo
let Koa = require('koa');
let bodyParser = require('koa-bod')
let app = new Koa();
app.use(bodyParser()); // 解析請求體的中介軟體
app.use(async (ctx, next) => {
    if (ctx.path === '/' && ctx.method === 'GET') {
        ctx.set('Content-Type', 'text/html;charset=utf8');
        ctx.body = `
        <form action="/" method="post">
            <input type="text" name="username" >
            <input type="text" name="password" >
            <input type="submit" >
        </form>
        `
    }
});
app.use(async (ctx, next) => {
    if (ctx.method === 'POST' && ctx.path === '/') {
        // 獲取表單提交過來的資料
        ctx.body = ctx.request.body;
    }
});
app.listen(3000);

複製程式碼

當post提交表單獲得表單資料,測試下結果

聊聊 koa 中介軟體

3、koa-better-body中介軟體

  • 是用來上傳檔案的中介軟體
  • 由於老的中介軟體都是基於koa1版本的generate函式實現的,在koa2中我們需要用koa-convert,可以將他們轉為基於Promise的中介軟體供Koa2使用

來個demo體驗下,我們把本地的1.txt檔案上傳到upload資料夾中。 1.txt內容為123456789

let Koa = require('koa');
let app = new Koa();
let betterBody = require('koa-better-body'); // v1外掛 
let convert = require('koa-convert'); // 將1.0的中介軟體 轉化成2.0中介軟體
app.use(convert(betterBody({
    uploadDir: __dirname //指定上傳的目錄 __dirname當前資料夾絕對路徑
})))
app.use(async (ctx, next) => {
    if (ctx.path === '/' && ctx.method === 'GET') {
        ctx.set('Content-Type', 'text/html;charset=utf8');
        ctx.body = `
        <form action="/" method="post" enctype="multipart/form-data">
            <input type="text" name="username" autoComplete="off">
            <input type="text" name="password" autoComplete="off">
            <input type="file" name="avatar">
            <input type="submit" >
        </form>
        `
    } else {
        return next();
    }
});
app.use(async (ctx, next) => {
    if (ctx.method === 'POST' && ctx.path === '/') {
        // 獲取表單提交過來的資料
        ctx.body = ctx.request.fields;
    }
});
app.listen(1000);
複製程式碼

看下上傳結果

聊聊 koa 中介軟體

內容也是正確的,我就不給大家展示拉

4、kao-views中介軟體

  • koa-views對需要進行檢視模板渲染的應用是個不可缺少的中介軟體,支援ejs, nunjucks等眾多模板引擎。

我們以ejs為例子

let Koa = require('koa');
let app = new Koa();
let views = require('koa-views');
app.use(views(__dirname,{
    extension:'ejs' //指定用ejs模板
}));
app.use(async (ctx,next)=>{
    // 渲染index.ejs
    await ctx.render('index',{name:'cgp',age:9,arr:[1,2,3]});
});
app.listen(3000);
複製程式碼
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1><%=name%></h1>
    <h1><%=age%></h1>
    <ul>
        <%arr.forEach(item=>{%>
             <li><%=item%></li>
        <%})%>
    </ul>
</body>
</html>

複製程式碼
  • 我們這裡寫的模板很簡單,就是輸出下name、age,然後迴圈下陣列

聊聊 koa 中介軟體

5、koa-static

let Koa = require('koa');
let server = require('koa-static');
let app = new Koa();
app.use(server(__dirname +'/public'));
app.listen(3000);
複製程式碼

6、koa自帶cookie用法

比如我們要儲存使用者名稱,保留使用者登入狀態時,會用到cookie。

共兩個方法
  • ctx.cookies.get()
  • ctx.cookies.set()

先來個demo測試,當輸入/write寫入cookie,當輸入/read讀到cookie

let Koa = require('koa');
let Router = require('koa-router');
let app = new Koa();
let router = new Router();
router.get('/read', (ctx, next) => {
    //有name讀name
    let name = ctx.cookies.get("name") || '沒有name';
    let age = ctx.cookies.get("age") || '沒有age';
    ctx.body = `${name}-${age}`;
});
router.get('/write', (ctx, next) => {
    ctx.cookies.set('name', 'cgp',{
        domain:'127.0.0.1', //寫入cookie所在的域名
        path:'/write',    // 寫入cookie最大的路徑
        maxAge:10*1000,    //Cookie最大有效時長
        httpOnly:false,  // 是否只用於http請求中獲取
        overwrite:false  // 是否允許重寫
    });
    ctx.cookies.set('age', '9');
    ctx.body = 'write Ok';
});
app.use(router.routes());
app.listen(4000);
複製程式碼
Cookie選項
  • domain:寫入cookie所在的域名
  • path:寫入cookie所在的路徑
  • maxAge:Cookie最大有效時長
  • expires:cookie失效時間
  • httpOnly:是否只用http請求中獲得
  • overwirte:是否允許重寫

看下執行結果吧

聊聊 koa 中介軟體

未完待續

對常用中介軟體原始碼感興趣可以參考下我總結

更多閱讀原文可以看這裡

都看到這裡啦,喜歡就點個贊吧

相關文章