Koa2自学笔记

13 篇文章 0 订阅
1 篇文章 0 订阅

在学习koa2之前先简单屡一下express、koa、koa2的关系;众所周知,这三者都是TJ大神的产物,那他们到底有什么不同呢?
express的异步操作是基于es5的回调函数嵌套,koa的异步操作是基于es6的generator函数来实现的,而koa2则是基于es7的async,await来实现的;

web框架语法备注
expresses5回调嵌套
koaes6Generator函数+yield语句+Promise
koa2es7async/await+Promise

基本用法

const Koa = require('koa')
const app = new Koa() // 创建了一个server实例
const main = ctx => {
    /* 
    Koa 提供一个 Context 对象,表示一次对话的上下文(包括 HTTP 请求和 HTTP 回复)。通过加工这个对象,就可以控制返回给用户的内容。
     */
    ctx.response.body = 'hello world'
}

// app.use((ctx) => {
//     ctx.response.body = 'hello world'
// })

app.use(main) //使用app.use方法加载main函数。
app.listen(3300) // 监听端口

HTTP Response 的类型

const Koa = require('koa')
const app = new Koa()

const main = ctx => {
    /* ctx.request.accepts()方法如果没有提供类型,则返回 所有 可接受的类型
    形如:[ 'text/html',
            'application/xhtml+xml',
            'image/webp',
            'image/apng',
            'application/xml'
        ]
    若没有找到匹配项则返回false;
    如果接收到任何类型的接收头,则会返回第一个类型。 因此,提供的类型的顺序很重要
    */
    if (ctx.request.accepts('xml')) { // 这里xml判断在先,所以会被先匹配到,所以返回'<data>Hello World</data>'
      ctx.response.type = 'xml';
      ctx.response.body = '<data>Hello World</data>';
    } else if (ctx.request.accepts('json')) {
      ctx.response.type = 'json';
      ctx.response.body = { data: 'Hello World' };
    } else if (ctx.request.accepts('html')) {
      ctx.response.type = 'html';
      ctx.response.body = '<p>Hello World</p>';
    } else {
      ctx.response.type = 'text';
      ctx.response.body = 'Hello World';
    }
  };
app.use(main)
app.listen(3300)

网页模板

const Koa = require('koa')
const app = new Koa()
const fs = require('fs')
// const fs = require('fs.promised')

// 这里把fs.readFile封装成了一个promise对象
let readFilePromise = function(url) {
        return new Promise((resolve,reject) => {
            fs.readFile(url, (err, data) => {
                if (err) {
                    reject(err);
                }
                resolve(data);
            })
        })
    }
const main = async ctx => {
    console.log(123);
    ctx.response.type = 'html';
    // 这里会等待 await 后的异步任务完成后,再继续往下执行
    let data = await readFilePromise('./1.html').then((data) => {
        return data;
    })
    ctx.response.body = data; 
  };

app.use(main)
app.listen(3300)

koa-route 模块

const Koa = require('koa')
const app = new Koa()
const route = require('koa-route')

const about = ctx => {
    ctx.response.type = 'html'
    ctx.response.body = '<a href="/">Index Page</a>'
}

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


app.use(route.get('/',main)) // 当请求路径为'/'时调用的时main处理函数
app.use(route.get('/about',about)) // 当请求路径为'/about'时调用的时about处理函数
app.listen(3300)

静态资源

const Koa = require('koa')
const app = new Koa()
const route = require('koa-route')
const server = require('koa-static') // 加载静态资源的模块
const path = require('path')
const fs = require('fs')

let readFilePromise = function(url) {
    return new Promise((resolve, reject) => {
        fs.readFile(url, (err, data) => {
            if (err) {
                reject(err);
            }
            resolve(data);
        })
    })
}


const about = ctx => {
    ctx.response.type = 'html'
    ctx.response.body = '<a href="/">Index Page</a>'
}

const main = async ctx => {
    ctx.response.type = 'html';
    let data = await readFilePromise('./1.html').then((data) => { // 实际可省略,详看异步中间件
        return data;
    })
    ctx.response.body = data;
};
const redirect = ctx => { // 重定向,访问'/redirect'会被重定向到根路径,返回的StatusCode为302
    ctx.response.redirect('/');
};
app.use(server(path.join(__dirname))) // 加载静态资源
app.use(route.get('/', main))
app.use(route.get('/about', about))
app.use(route.get('/redirect', redirect))
app.listen(3300)

中间件与中间件栈

const Koa = require('koa');
const app = new Koa();

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的顺序决定(下面这三个家伙的顺序)
app.use(one);
app.use(two);
app.use(three);
/*
>> one
>> two
>> three
<< three
<< two
<< one
  */
app.listen(3300);
  1. 最外层的中间件首先执行。
  2. 调用next函数,把执行权交给下一个中间件。
  3. 最内层的中间件最后执行。
  4. 执行结束后,把执行权交回上一层的中间件。
  5. 最外层的中间件收回执行权之后,执行next函数后面的代码。

异步中间件

const fs = require('fs');
const Koa = require('koa');
const app = new Koa();

let readFilePromise = function(url) {
  return new Promise((resolve,reject) => {
      fs.readFile(url, (err, data) => {
          if (err) {
              reject(err);
          }
          resolve(data);
      })
  })
}
const main = async function (ctx, next) {
  ctx.response.type = 'html';
  let data = await readFilePromise('./1.html') // await的作用其实就是替代了then方法,将resolve的值直接返回,使用起来更加方便。
  ctx.response.body = data
};

app.use(main);
app.listen(3300);

中间件的合成

const Koa = require('koa')
const app = new Koa()
const compose = require('koa-compose') // koa-compose模块可以将多个中间件合成为一个,我的理解作用是可以不用写多个app.use了
const router = require('koa-route')
const fs = require('fs.promised')
const server = require('koa-static')
const path = require('path')
/*为了方便处理错误,最好使用try...catch将其捕获。但是,为每个中间件都写try...catch太麻烦,
我们可以让***最外层***的中间件,负责所有中间件的错误处理。*/
const handle = async (ctx, next) => {
    try {
        await next()
    } catch(err) {
        ctx.response.status = err.statusCode || err.status || 500
        ctx.response.body = {
            message: err.message
        }
    }
}

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

const main = async ctx => {
    let data = await fs.readFile('./1324.html', 'utf8')
    // ctx.throw(500) // 这条语句可以使程序抛出错误被最外层的handle函数捕捉到(原因请参考中间件与中间件栈里的说明)
    ctx.response.type = 'html';
    ctx.response.body = data
};
const middlewares = compose([handle, logger, main]); // 把多个中间件整合到一起(少些app.use)
app.use(server(path.join(__dirname))) 
app.use(router.get('/',middlewares)) // 用路由处理对应的中间件
// app.use(middlewares);
app.listen(3300)

表单

const Koa = require('koa')
const koaBody = require('koa-body') // koa-body模块可以用来从 POST 请求的数据体里面提取键值对
const app = new Koa()

const main = async function(ctx) {
  const body = ctx.request.body;
  if (!body.name) ctx.throw(400, '.name required');
  ctx.body = { name: body.name };
};

app.use(koaBody());
app.use(main);
app.listen(3300);

打开另一个命令行窗口,运行下面的命令。

$ curl -X POST --data “name=Jack” 127.0.0.1:3300
{“name”:“Jack”}

$ curl -X POST --data “name” 127.0.0.1:3300
name required

 

文件上传

const Koa = require('koa');
const koaBody = require('koa-body');
const app = new Koa();
const path = require('path');
const fs = require('fs');
const main = async (ctx) => {
    const file = ctx.request.body.files.upload || {}
    // ctx.request.body.files.upload 为文件对象
    const filePath = path.join(__dirname, file.name) // 保存文件的路径,当前路径加上文件名
    const reader = fs.createReadStream(file.path) // 把上传的文件读出来,赋值给reader成为一个可读的对象
    const writer  = fs.createWriteStream(filePath) // 根据路径生成一个可写的writer对象
    reader.pipe(writer) // 正式执行写入操作
    ctx.response.body = 'uploadSuccess!'
};

app.use(koaBody({ multipart: true }));
app.use(main);
app.listen(3300);

参考资料http://www.ruanyifeng.com/blog/2017/08/koa.html

参考资料https://koa.bootcss.com/#application

喜欢博主的可以点赞关注一下

---------------------------------------------------------------   END   ------------------------------------------------------------------

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值