Koa2基础入门教程

一、koa安装与hello world示例:

koa需要node v7.6.0以上(因为需要ES6)

“`npm install koa –save“`

习惯性加上save,不加也可以。

koa的hello world示例

const Koa = require('koa');
const app = new Koa();
app.use(async(ctx)=>{
    ctx.body = 'hello koa!';
})
app.listen(3000);

这个示例很简单,从node_modules中导入Koa类,然后实例化给app,通过app.use(中间件处理函数)来触发接受请求(每当有请求的时候就会按编写顺序和next堆栈方式触发这些所有的中间件函数),通过koa语法糖创建监听端口.

ctx.body即是我们显示在网页上的内容。

二、next函数与中间件调用顺序

官网的表述:

Koa 的中间件通过一种更加传统(您也许会很熟悉)的方式进行级联,摒弃了以往 node 频繁的回调函数造成的复杂代码逻辑。 然而,使用异步函数,我们可以实现”真正” 的中间件。与之不同,当执行到 yield next 语句时,Koa 暂停了该中间件,继续执行下一个符合请求的中间件(‘downstrem’),然后控制权再逐级返回给上层中间件(‘upstream’)。

下面的例子在页面中返回 “Hello World”,然而当请求开始时,请求先经过 x-response-time 和 logging 中间件,并记录中间件执行起始时间。 然后将控制权交给 reponse 中间件。当一个中间件调用next()函数时,函数挂起并控件传递给定义的下一个中间件。在没有更多的中间件执行下游之后,堆栈将退出,并且每个中间件被恢复以执行其上游行为。

// 中间件函数参数 第一个context上下文对象 第二个next函数,用于控制koa的执行顺序
// 接下来我们编写三个中间件使得koa能够反馈响应并打印到控制台上
// 打印请求方式和请求地址
const Koa = require('koa');
const app = new Koa();
// 大致意义就是堆栈类似的调用方式:x-response-time -> logger -> response ->logger ->x-response-time
app.use(async (ctx, next) => {
    const start = Date.now();
    console.log("x-response-time was used at 1")
    await next();
    console.log("x-response-time was used at 2")
    const ms = Date.now() - start;
    // 这句话的意义是设置返回头 response headers
    ctx.set('X-Response-Time', `{ms}ms`);
});

// logger
app.use(async (ctx, next) => {
    const start = Date.now();
    console.log("logger was used at 1")
    await next();
    console.log("logger was used at 2")
    const ms = Date.now() - start;
    console.log(`{ctx.method} {ctx.url} -{ms}`);
});

// response

app.use(async ctx => {
    console.log("response was used at 1")
    ctx.body = 'Hello World';
});

app.listen(3000);

打印结果:

x-response-time was used at 1
logger was used at 1
response was used at 1
logger was used at 2
GET / – 12
x-response-time was used at 2

大致意义就是堆栈类似的调用方式:x-response-time,next之前的内容 -> logger,next之前的内容 -> response,无next,全部调用 ->logger,next之后的内容 ->x-response-time,next之后的内容->结束

三、request对象和参数的获取

get请求:

我们可以通过
“`ctx.request“`属性获取统一的request对象,获取其中url/query的内容

const Koa = require("koa");
const app = new Koa();
app.use(async (ctx) => {
  let url = ctx.url;

  let request = ctx.request;
  // query返回的是格式化好的参数对象,querystring则是请求字符串,
  let req_query = request.query; 
  let req_query_string = request.querystring;
  // 也可以直接通过ctx获取
  let ctx_query = ctx.query;
  let ctx_querystring = ctx.querystring;
  ctx.body = {
    url,
    req_query,
    req_query_string,
    ctx_query,
    ctx_querystring
  };
  console.log(url);
});

app.listen(3000);
console.log("server start at http://127.0.0.1:3000");

post请求:

1.使用第三方的koa-bodyparser中间件,在使用后从ctx.request.body中获取post的数据(对象)

const Koa = require("koa");
const app = new Koa();
const bodyparser = require("koa-bodyparser");
// koa-bodyparser需要先引用
app.use(bodyparser());

app.use(async (ctx) => {
  if (ctx.url === "/" && ctx.method === "GET") {
    // 显示表单界面
    let html = `
        <h1>AX Koa2 request post</h1>
        <form action="/" method="POST">
            <p>userName:</p>
            <input type="text" name="userName"/><br />
            <p>password:</p>
            <input type="password" name="password"/><br />
            <p>website:</p>
            <input name="website" /><br />
            <button type="submit">提交</button>
        </form> 
        `;
    ctx.body = html;
  } else if (ctx.url === "/" && ctx.method === "POST") {
    // 导入bodyparser后,直接从body中拿取post
    let postData = ctx.request.body;
    ctx.body = postData;
  } else {
    ctx.body = "<h1>404!</h1>";
  }
});

app.listen(3000, () => {
  console.log("server started at http:127.0.0.1:3000/");
});

  1. 手写解析(原理剖析,非重点)

    注意这里的

   ctx.req.addListener("data", (data) => {
           postData += data;
         });

     ctx.req.on("end", function () {
       let parseData = parseQueryStr(postData);
       resolve(parseData);
     });

这两种监听,都是通过ctx.req对象实现,ctx.req就是原生的nodejs对象里的http/https板块内容

“`js
const Koa = require(“koa”);
const app = new Koa();
app.use(async (ctx) => {
if (ctx.url === “/” && ctx.method === “GET”) {
// 显示表单界面
let html = `

AX Koa2 request post

userName:

password:

website:


`;
ctx.body = html;
} else if (ctx.url === “/” && ctx.method === “POST”) {
let postData = await parsePostData(ctx);
ctx.body = postData;
} else {
ctx.body = “

404!

“;
}
});

function parsePostData(ctx) {
return new Promise((resolve, reject) => {
try {
let postData = “”;

     // 原生node设置数据监听
     //当node.js后台收到post请求时,
     //会以buffer的形式将数据缓存起来。
     //Koa2中通过ctx.req.addListener('data', ...)这个方法监听这个buffer。
     ctx.req.addListener("data", (data) => {
       postData += data;
     });
     // buffer流结束触发
     ctx.req.on("end", function () {
       let parseData = parseQueryStr(postData);
       resolve(parseData);
     });
   } catch (error) {
     reject(error);
   }
 });

}

function parseQueryStr(queryStr) {
let queryData = {};
let queryStrList = queryStr.split(“&”);
console.log(queryStrList);
console.log(queryStrList.entries());
for (let [index, queryStr] of queryStrList.entries()) {
let itemList = queryStr.split(“=”);
console.log(itemList);
// 原生方法decodeURIComponent
queryData[itemList[0]] = decodeURIComponent(itemList[1]);
}
return queryData;
}

app.listen(3000, () => {
console.log(“server started at http:127.0.0.1:3000/”);
});

“`

## 四、路由的使用

首先我们可以通过原生手段,解析url从而来实现不同页面的分发:

准备三个html文件:

在这里插入图片描述

基本框架类似

const Koa = require("koa");
const fs = require("fs");

const app = new Koa();
async function render(page) {
  return new Promise((resolve, reject) => {
    let pageUrl = `./page/${page}`;
    // 使用fs,用utf-8指定读取编码
    fs.readFile(pageUrl, "utf-8", (err, data) => {
      if (err) {
        reject(err);
      } else {
        resolve(data);
      }
    });
  });
}

async function route(url) {
  let page = "404.html";
  switch (url) {
    case "/":
      page = "index.html";
      break;
    case "index":
      page = "index.html";
      break;
    case "/todo":
      page = "todo.html";
      break;
    default:
      break;
  }
  let html = await render(page);
  return html;
}
app.use(async (ctx) => {
  let url = ctx.request.url;
  let html = await route(url);
  ctx.body = html;
});

app.listen(3000);

显然这种方式比较缓慢,于是我们使用koa-router来实现路由的分发:

大致上分为以下步骤

  • 导入koa-router

  • 实例化koa-router

  • 通过实例化对象的get/post/put/delete等方法(指定请求方式)来创建路由,第一个参数为路由(字符串),第二个参数为触发的中间件async函数。

  • 挂载到实例化的app上,通过app.use

    const Koa = require('koa')
    const Router = require('koa-router')
    const app = new Koa();
    const router = new Router();
    
    router
      .get('/', (ctx, next) => {
      ctx.body = 'hello ax';
      })
      .get('/todo', (ctx, next) => {
          ctx.body = 'todo page';
      })
    // 确定路由请求
    app
      .use(router.routes())
      .use(router.allowedMethods());
    app.listen(3000, () => {
      console.log("starting at port 3000")
    })
    

通过koa-router实现多级路由:

  1. 添加层级:比如将/ax,/todo变为/home/ax,/home/todo

    我们可以通过实例化router对象的时候,在参数中加入prefix

    const Koa = require('koa')
    const Router = require('koa-router')
    const app = new Koa();
    // 程序层级
    const router = new Router(
       {
           // 前缀
           prefix: '/ax'
       }
    );
    
    router
       .get('/', (ctx, next) => {
           ctx.body = 'hello ax';
       })
       .get('/todo', (ctx, next) => {
           ctx.body = 'todo page';
       })
    // 确定路由请求
    app
       .use(router.routes())
       .use(router.allowedMethods());
    app.listen(3000, () => {
       console.log("starting at port 3000")
    })
    
  2. 多级路由和多前缀实现

    创建父路由并将子路由挂载到其下

    const Koa = require('koa')
    const Router = require('koa-router')
    const app = new Koa();
    // 子路由
    let home = new Router();
    home.get('/ax', async (ctx) => {
       ctx.body = "home ax page";
    })
       .get('/todo', async (ctx) => {
           ctx.body = "home toDo page";
       })
    let page = new Router();
    page.get('/ax', async (ctx) => {
       ctx.body = "page ax page";
    })
       .get('/todo', async (ctx) => {
           ctx.body = "page toDo page";
       })
    // 父级路由
    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-static第三方中间件实现静态资源的加载

使用步骤:

  • 导入koa-static

  • 作为中间件调用导入的函数并且将其挂载到示例(以要开辟的空间的路径使用

    const Koa = require('koa')
    const path = require('path')
    // 导入koa-static
    const static = require('koa-static')
    const app = new Koa();
    const staticPath = './static';
    // 路径字符串作为初始化值
    app.use(static(path.join(__dirname, staticPath)))
    app.use(async (ctx) => {
      console.log(path.join(__dirname, staticPath))
      ctx.body = "hello world"
    })
    app.listen(3000)
    

到此koa的基本内容结束,关于cookies,ejs等其他前后不分离的开发形式请自行参考官方文档

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇