nodejs koa框架使用

1: KOA 是express 打造的下一代web 开发框架提供更小更强的的核心功能,通过Promise 、async/await 进行异步编程,koa 可以不使用回调,解决了回调地狱的问题

blueBird 是nodejs 最出名的Primise 实现,除了实现标准的promise 之外,还提供了包装方法,可以快速得奖回调包装微Promise

2:bluebird 的使用

npm install bluebird -save

方法签名: bluebird.promisifyAll(target,options);

target 表示需要包装的对象,如果target是普通对象,包装后api 只会被当前对象持有,如果是原型对象,则会被所有的实例持有

options:

suffix :后缀,默认是Async

mutiArgs : 是否允许多个回调参数,默认是false,为true时,bluebird 将所有参数传入一个数组,promise.then() 接受该数组,从而可以得到多个参数
编程案例:

复制代码
const bluebird = require('bluebird');
const fs = require('fs');

bluebird.promisifyAll(fs);

//回调
fs.readFile('文件路径',{encoding:'utf8'},(err,data)=>{
  if(err){
    console.error(err);
    return;
  }
  console.log(data);
});

//Promise
fs.readFileAsync('文件路径',{encoding:'utf8'},(err,data)=>{
   console.log(data);
}).catch((err)=>{
  console.error(err);
});

编写第一个koa 程序:

复制代码
//导入koa 模块
const Koa = require('koa');
//实例化应用
const app = new Koa();

//中间件
app.use(async (ctx)=>{
    ctx.body = 'hello world';
});

app.listen(8080,()=>{
    console.log('start up 8080');
})

//Context 成为koa 的文件上下文,包含了对象的请求、响应、context 可以理解为一个容器

//常用的属性和方法

//ctx.request koa的请求对象一般不直接使用,通过别名来访问

//ctx.response koa的响应对象一般不直接使用,通过别名来访问

//ctx.state 自定义数据存储,比如中间件需要往请种种挂在变量,就可以存放在

//state 后续中间件可以读取

//ctx.throw() 抛出http 异常

//ctx.headers 请求报头,ctx.request.headers 的别名

//ctx.method 请求方法,ctx.request.method 的别名

//ctx.url 请求连接,ctx.request.url 的别名

//ctx.path 请求路径,ctx.request.path 的别名

//ctx.query 请求参数,ctx.request.query 的别名,解析后的get请求参数对象

//ctx.host 请求域名地址,ctx.request.host 的别名

//ctx.ip 请求客户端ip,ctx.request.ip 的别名

//ctx.ips 请求ip列表,ctx.request.ips 的别名 ,反向代理环境下IP列表

//ctx.get() 读取请求报头,ctx.request.get 的别名

//ctx.body 响应内容,支持字符串,数组,对象,buffer 等,,ctx.response.get 的别名

//ctx.type 响应体类型,ctx.response.type 的别名

//ctx.redirect()重定向 ctx.response.redirect 的别名

//ctx.set() 设置相应报头 ,ctx.response.set 的别名

代码验证:

复制代码
//导入koa 模块
const { method } = require('bluebird');
const Koa = require('koa');
//实例化应用
const app = new Koa();

app.proxy = true;

app.use(async (ctx)=>{
    ctx.set('x-version','1.0');
    ctx.body = {
        method: ctx.method,
        ip: ctx.ip,
        path: ctx.path,
        url: ctx.url,
        query: ctx.query,
        headers: ctx.headers
    } 
});


app.listen(8080,()=>{
    console.log('start up 8080');
})

执行结果:

http://localhost:8080/?name=刘亦菲

复制代码
{"method":"GET","ip":"::ffff:127.0.0.1","path":"/","url":"/?name=%E5%88%98%E4%BA%A6%E8%8F%B2","query":{"name":"刘亦菲"},"headers":{"host":"localhost:8080","connection":"keep-alive","sec-ch-ua":"\"Not;A=Brand\";v=\"99\", \"Google Chrome\";v=\"139\", \"Chromium\";v=\"139\"","sec-ch-ua-mobile":"?0","sec-ch-ua-platform":"\"Windows\"","upgrade-insecure-requests":"1","user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36","accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","sec-fetch-site":"none","sec-fetch-mode":"navigate","sec-fetch-user":"?1","sec-fetch-dest":"document","accept-encoding":"gzip, deflate, br, zstd","accept-language":"zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7"}}

Cookie 的设置和读取

复制代码
//导入koa 模块
const { method } = require('bluebird');
const Koa = require('koa');
//实例化应用
const app = new Koa();

app.keys = ['13wweeiioo'];
//cookie 设置和读取
app.use(async (ctx)=>{
     ctx.cookies.set('logined',1,{
        signed: true,
        httpOnly: true,
        maxAge: 3600 * 24 * 1000 //有效期一天
     });
     ctx.body = "ok la";
});

app.listen(8080,()=>{
    console.log('start up 8080');
})

中间件

与expres 的中间件类似,Koa 的中间建也你能访问请求对象响应对象和next 函数通常用来执行以下任务:

执行逻辑

更改请求和响应

结束请求-相应周期

调用下一个中间建

错误处理

koa 使用async /await 来进行异步编程,不需要执行回调函数,直接对ctx.body 赋值就行

Koa 的中间件是一个表中的异步函数,签名如下:

async function middleware(ctx,next);

ctx 是上下文

next 下一个中间件

运行完代码逻辑,将需要传递的数据挂在到ctx.state ,并且调用 await.next() 才能将请求转发给下一个中间件

(洋葱卷模型)
代码案例:

复制代码
const Koa = require('koa');
//实例化应用
const app = new Koa();

async function mid1(ctx,next){
   console.log('mid1 begin');
   await next();
   console.log('mid1 end');
}

async function mid2(ctx,next){
 console.log('mid2 begin');
   await next();
   console.log('mid2 end');
}

app.use(mid1);
app.use(mid2);

app.use(async (ctx)=>{
    console.log('request route!');
    ctx.body = 'Hello world';
});

app.listen(8080,()=>{
    console.log('start up 8080');
})

执行结果:

mid1 begin

mid2 begin

request route!

mid2 end

mid1 end

日志中间件

复制代码
const Koa = require('koa');
//实例化应用
const app = new Koa();

async function logger(ctx,next) {
    const start = Date.now();
    await next();
    console.log(`${ctx.method} ${ctx.path} costTime:${Date.now() - start}ms`); 
}

app.use(logger); //注册日志中间件
app.use(async (ctx)=> {
      ctx.body = 'Hello World';
});

app.listen(8080,()=>{
    console.log('start up 8080');
})

cookie 解析中间件:

复制代码
const Koa = require('koa');
//实例化应用
const app = new Koa();

//定义cookie中间件
async function cookieParser(ctx,next) {
    const headerCookie = ctx.headers.cookie;
    ctx.state.cookies = {};
    if(headerCookie){
       const cookies = headerCookie.split(";");
       cookies.forEach(cookie => {
        const parts = cookie.split('=');
        ctx.state.cookies[parts[0] = parts[1]];//挂在 ctx.state.cookies
       });
       await next();
    }
}

//注册中间件
app.use(cookieParser);

//使用中间建
app.use(async (ctx)=>{
   ctx.body = ctx.state.cookies;
});

//监听服务启动
app.listen(8000,()=>{
    console.log('start up 8000');
})

KOA 路由:

安装路由模块:

npm install koa-router -save

C:\Users\Lei.Wang170\Desktop\koa-01>npm install koa-router -save 这种写法已经不适用了

npm warn deprecated koa-router@14.0.0: Please use @koa/router instead, starting from v9!

使用新的安装命令:

C:\Users\Lei.Wang170\Desktop\koa-01>npm install @koa/router -save

added 1 package in 922ms

1 package is looking for funding

run npm fund for details
路由案例:

复制代码
const Koa = require('koa');
const Router = require('koa-router');
//实例化应用
const app = new Koa();

const router = new Router();

//路由定义
router.get('/',async (ctx)=>{
    ctx.body ='hello world';
});

router.get('/user',async (ctx)=>{
 ctx.body ='hello user';
});

//挂载路由
app.use(router.routes());
app.use(router.allowedMethods());

app.listen(8000,()=>{
    console.log('start up 8000');
})

错误处理:

复制代码
const Koa = require('koa');
//实例化应用
const app = new Koa();

//自定义中间件
async function errorHandler(ctx,next) {
      try {
        await next();
      } catch (error) {
        ctx.status = error.status || 500;
        ctx.body = `System Error: ${error.message}`;
      }
}
app.use(errorHandler);  //挂在中间件不需要括号,挂在路由需要括号()

//抛出异常
app.use((ctx)=>{
    ctx.throw(403,'Forbidden');
});

app.listen(8000,()=>{
    console.log('start up 8000');
})

注意错误处理器一定在在使用之前被挂载上,否则不成功

多个错误处理器的场景:

同时需要响应错误给调用端,并且要记录日志

复制代码
const Koa = require('koa');
//实例化应用
const app = new Koa();

//自定义中间件
async function errorHandler(ctx,next) {
      try {
        await next();
      } catch (error) {
        ctx.status = error.status || 500;
        ctx.body = `System Error: ${error.message}`;
      }
}

//错误日志记录中间件
async function loggerHandler(ctx,next) {
      try {
        await next();
      } catch (error) {
       console.log(`error: ${ctx.path} ${ctx.ip}`);
       throw error;
      }
}

app.use(errorHandler);  //挂在中间件不需要括号,挂在路由需要括号()
app.use(loggerHandler); 
//抛出异常
app.use((ctx)=>{
    ctx.throw(403,'Forbidden');
});

app.listen(8010,()=>{
    console.log('start up 8010');
})

执行结果

路由级别的中间件

复制代码
const Koa = require('koa');
const Router = require('koa-router');
const router = new Router();
//实例化应用
const app = new Koa();
//错误日志记录中间件
async function loggerHandler(ctx,next) {
        console.log(`error: ${ctx.path} ${ctx.ip}`);
        await next();      
}

router.get('/',loggerHandler,async (ctx)=>{
    ctx.body ='hello world';
});

app.listen(8010,()=>{
    console.log('start up 8010');
})

模块化路由:

student.js

const Router = require('koa-router');

//定义带有前缀的路由

const router = new Router({ prefix: '/student' });

//路由定义

router.get('/name', (ctx)=>{

ctx.body ='student';

});

module.exports = router;

teacher.js

const Router = require('koa-router');

//定义带有前缀的路由

const router = new Router({ prefix: '/teacher' });

//路由定义

router.get('/id', (ctx)=>{

ctx.body ='teacher';

});

module.exports = router;

koa.js

const Koa = require('koa');

//实例化应用

const app = new Koa();

const stuRouter = require('./routes/student');

const teaRouter = require('./routes/teacher');

app.use(stuRouter.routes()).use(stuRouter.allowedMethods());

app.use(teaRouter.routes()).use(teaRouter.allowedMethods());

app.listen(8010,()=>{

console.log('start up 8010');

})

koa-ejs 模板渲染:

npm install koa-ejs --save