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 = `
        

AX Koa2 request post

userName:


password:


website:


`
; ctx.body = html; } else if (ctx.url === "/" && ctx.method === "POST") { // 导入bodyparser后,直接从body中拿取post let postData = ctx.request.body; ctx.body = postData; } else { ctx.body = "

404!

"
; } }); 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板块内容

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文件:

Koa2基础入门教程_第1张图片

基本框架类似

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等其他前后不分离的开发形式请自行参考官方文档

你可能感兴趣的:(node.js,后端,javascript)