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的执行,请求从最外层进去,又从最里层出来。
中间件的功能包括:
-
执行任何代码
-
修改请求和响应请求对象
-
终结请求-响应循环
-
调用堆栈中的下一个中间件
如果get、post回调函数中,没有next参数,那么就匹配上第一个路由,就不会往下匹配了。如果想往下匹配的话,那么就需要写next()。
app.use('/',function(){});
不管app.use
和router
的书写顺序如何,都是先执行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 ,可以看到运行结果:
可以看到区别,.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及node有一个初步的印象和概念。
课后作业:
用koa框架实现一个web页面。
进阶:本地json存储,实现增删改查。
参考: