KOA框架基础知识分享

Koa 就是一种简单好用的 Web 框架,node可以在ssr服务端渲染,bff层,接口聚合,削减api,或处理api数据等方面应用,减小前端代码复杂度,为企业节省成本,让吞吐率更高。

 

本文是我在实际业务中,用koa框架作为BFF层(Back-end For Front-end),也叫中间层,聚合接口,压缩图片,提高系统页面性能实践后,针对其他同学,普及node、koa基础知识的文档。

 

本次分享的目的:

  • 让大家对node不再陌生
  • 能上手利用node参与一些性能优化,
  • 提升个人的技术能力和技术视野

 

以下是正文

 

一、简介

koa 是由 Express 原班人马打造的,致力于成为一个更小、更富有表现力、更健壮的 Web 框架。使用 koa 编写 web 应用,通过组合不同的 generator,可以免除重复繁琐的回调函数嵌套,并极大地提升错误处理的效率。koa 不在内核方法中绑定任何中间件,它仅仅提供了一个轻量优雅的函数库,使得编写 Web 应用变得得心应手。

 

二、KOA代码结构

koa 非常小巧,总共就 4 个文件,每个文件的功能也十分单一,文件名也清楚的反应了文件功能。

koa 的文件结构

├── application.js
├── context.js
├── request.js
└── response.js
复制代码
  • request.js

    主要针对 http 的 request 对象提供了改对象的大量的 get 方法,文件主要是用来获取 request 对象属性。

  • response.js

    主要针对 http 的 response 对象提供了该对象的大量 set 方法;该文件主要是用来设置 response 对象属性。

  • context.js

    koa 引入了上下文对象的概念,即 ctx,这里所谓的上下文对象实际上是 request 和 response 两个对象的并集,request 和 response 分别通过代理的形式,将自己的方法委托给 ctx。那样我们就可以用 ctx 同时操作两个对象,来简化操作。

  • application.js

    该文件是整个 koa 的核心,简单来说主要有两大功能: 挂载真实请求到 ctx 下,封装中间件的执行顺序

 

三、KOA和express的区别

于是二者的使用区别通过表格展示如下:

  koa(Router = require('koa-router')) express(假设不使用app.get之类的方法)
  koa(Router = require('koa-router')) express(假设不使用app.get之类的方法)
初始化 const app = new koa() const app = express()
实例化路由 const router = Router() const router = express.Router()
app级别的中间件 app.use app.use
路由级别的中间件 router.get router.get
路由中间件挂载 app.use(router.routes()) app.use('/', router)
监听端口 app.listen(3000) app.listen(3000)

上表展示了二者的使用区别,从初始化就看出koa语法都是用的新标准。在挂载路由中间件上也有一定的差异性,这是因为二者内部实现机制的不同。其他都是大同小异的了。

与 express,hapi,eggjs 比起来,koa 真的十分小巧,以至于不能称作一种框架,可以看做一种库,但这并不妨碍 koa 生态的发展。

express 当初也是大而全的框架,慢慢的把各种功能已中间件的形式抽离出来,koa 可以看做这种思想的一种实现。大而全的框架主要存在起初的学习成本高,功能冗余等问题,使用 koa 对于初次使用 nodejs 开发 web 的人员非常友好,对于初学者来说,建议从 koa 入手,使用不同的中间件来实现不同的功能,对于了解 web 开发有很大帮助。

四、中间件

1、什么是中间件?

中间件就是匹配路由(匹配任何路由或者特定的路由,其作用比如打印日志,查看权限)之前或者匹配路由完成之后所得一系列操作,功能有:
1.执行任何代码
2.修改请求和和响应对象
3.终结请求-响应循环
4.调用堆栈中的下一个中间件
通过next来实现

在express 中间件(Middleware) 是一个函数,它可以访问请求对象(request object(req)),响应对象(response object()res)和web应用中处理请求-相应循环流程中的中间件,一般被命名为next的变量。在Koa中中间件和express有点类似。

 

经典的洋葱图概念能很好的解释next的执行,请求从最外层进去,又从最里层出来。

KOA框架基础知识分享

 

 

中间件的功能包括:

  • 执行任何代码

  • 修改请求和响应请求对象

  • 终结请求-响应循环

  • 调用堆栈中的下一个中间件

如果get、post回调函数中,没有next参数,那么就匹配上第一个路由,就不会往下匹配了。如果想往下匹配的话,那么就需要写next()。

app.use('/',function(){});

  不管app.userouter的书写顺序如何,都是先执行app.use再执行router

Koa应用可以使用如下几种中间件:

  • 应用级中间件

  • 路由级中间件

  • 错误处理中间件

  • 第三方中间件

可以写两个参数,第一个是匹配的路径,第二个是回调函数,第一个参数可以省略

 

五、实践

1、安装

检查node版本

$ node -v
v14.15.1

Koa 必须使用 7.6 以上的版本。如果你的版本低于这个要求,就要先升级 Node。

你可以使用自己喜欢的版本管理器快速安装支持的 node 版本:

$ nvm install 7
$ npm i koa
$ node my-koa-app.js

2、架设HTTP服务

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

// 本地服务
app.listen(3000, ()=>{
  console.log('http://localhost:3000')
})

显示Not Found,因为我们没有给内容,所以显示这个。

3、Context 对象

Koa 提供一个 Context 对象,表示一次对话的上下文(包括 HTTP 请求和 HTTP 回复)。

demo如下:

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

const main = ctx => {
  ctx.body = 'Hello 星火组';
};

app.use(main);
// 本地服务
app.listen(3000, ()=>{
  console.log('http://localhost:3000')
})

 

HTTP Response类型:

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

// const main = ctx => {
//   ctx.body = 'Hello 星火组';
// };

//HTTP Response 的类型
// const main = ctx => {
//   if (ctx.request.accepts('xml')) {
//     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';
//   }
// };

const main = ctx => {
  ctx.response.type = 'html';
  ctx.response.body = fs.createReadStream('template.html');
};

app.use(main);
// 本地服务
app.listen(3000, ()=>{
  console.log('http://localhost:3000')
})

 

node 项目实操查看ctx返回

https://koajs.com/#context。官方文档介绍。

 

4、router 路由

上面代码中,根路径/的处理函数是main/about路径的处理函数是about

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

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));
app.use(route.get('/about', about));
app.listen(3000, ()=>{
  console.log('http://localhost:3000')


})

 5、中间件

// 引入Koa模块
const Koa = require('koa');
// 引入Koa-router
const Router = require('koa-router');
 
// 实例化Koa模块
const app = new Koa();
// 实例化路由模块
const router = new Router();
 
// Koa 中间件
// app.use('/',function(){});   //可以写两个参数,第一个是匹配的路径,第二个是回调函数,第一个参数可以省略
 
// 匹配任何路由之前打印日期
app.use(async (ctx,next)=>{
  console.log(new Date());
  await next();  //当前路由匹配完成以后继续向下匹配
});
 
// 配置路由
// ctx 上下文 context,  包含了request和response等信息
router.get('/',async (ctx)=>{
  ctx.body = '网站首页';  //返回数据    相当于:原生里面的res.writeHead()  res.end()
});
 
// 路由级中间件
// 匹配带news路由以后继续向下匹配路由
router.get('/news',async (ctx,next)=>{
  console.log('这是一个新闻路由');
  await next();
});
router.get('/news',async (ctx)=>{
  ctx.body = '新闻列表页面';
});
 
router.get('/login',async (ctx)=>{
  ctx.body = '网站登录页面';
});
 
// 启动路由
app
  .use(router.routes())   /*启动路由*/
  .use(router.allowedMethods());  //作用:当请求出错时处理逻辑
/*
 * router.allowedMethods()作用: 这是官方文档的推荐用法,我们可以
 * 看到 router.allowedMethods()用在了路由匹配 router.routes()之后,所以在当所有
 * 路由中间件最后调用.此时根据 ctx.status 设置 response 响应头
 *
 */
 
// 监听3000端口
app.listen(3000,()=>{
  console.log('starting at port 3000');
});

6、获取请求数据

const Koa = require('koa')
const app = new Koa()
const Router = require('koa-router')
const router = new Router()
 
router.get('/data', async (ctx , next)=> {
  let url = ctx.url
 
  // 从ctx的request中拿到我们想要的数据
  let data = ctx.request.query
  let dataQueryString = ctx.request.querystring
 
  ctx.body = {
    url,
    data,
    dataQueryString
  }
})
 
app.use(router.routes())
 
app.listen(3333, ()=>{
  console.log('server is running at http://localhost:3333')
})

在浏览器里输入http://localhost:3333/data?user=wuyanzu&id=123456 ,可以看到运行结果:

KOA框架基础知识分享

 

 

可以看到区别,.query返回的结果是对象,而.querystring返回的是字符串,这个很好理解。(chrome插件显示成json格式)

如果遵从 RESTful 规范,比如请求要以 '/user/:id'的方式发出的话,我们可以用下面的例子来获取到想要的数据。

router.get('/data/:id', async (ctx, next) => {
 
  // 也从ctx中拿到我们想要的数据,不过使用的是params对象
  let data = ctx.params
 
  ctx.body = data
})

浏览器运行 http://localhost:3333/data/4396 看到结果:

KOA框架基础知识分享

 

 以上,我们通过上面的代码和描述,已经对koa及node有一个初步的印象和概念。

 

课后作业:

用koa框架实现一个web页面。

进阶:本地json存储,实现增删改查。

 

参考:

KOA官网

【从前端到全栈】- koa快速入门指南

上一篇:Devops 开发运维高级篇之容器管理


下一篇:vue+element-ui+ koa-multer 上传图片