接着前面的文章,我们慢慢得把菜鸟前端写接口这件事向前推进。今天主要介绍koa的使用,这是完成后端接口中非常关键的一步。 OK,准备好小板凳,我要开始讲故事了。
什么是koa?
先看下官方的解释:基于Node.js平台的下一代web开放框架。这一句话的关键字是web框架,那啥是web框架呢?类似的框架有express,可以跟她类比一下(不好意思,代码敲久了,看谁都像那个她了)。如果有不熟悉express的朋友,我在这样类比一下:我想在一个水池里养一些小动物,比如我可以在这个池子里养一些小鱼,那么一年后我就能打捞一些小鱼出来;或者我们可以在这个池子里养一些青蛙,那一年后我们也可以获得一批成年青蛙;或者我们可以养一些黄鳝,那么一年后我们能得到一些成年黄鳝......
我们都知道进行前后端交互需要进行http请求,它存在request=> 处理数据 => response这第三个过程对吧。我们再来类比一下:我们将小鱼苗投向水池就像http请求中的request部分,小鱼在水池生存过程就像处理数据的过程,而打捞鱼儿就类似response的部分。而koa作为一个web框架,就相当把投放和捕捞这两部分都帮我们完成了,我们只需要专注于水池生存的这一个部分。换句话说:koa处理了request和response,我们需要做的就是编写中间数据处理的过程,这部分叫做中间件。
中间件这个词也挺形象,这个跟我们生活中的中间商很类似。我老家是在中国很南的地方,有花炮之乡的美名,所以我的家乡是属于花炮的生产商。但是在我们临市经常会有这样一批人,他们购买我们的花炮,然后在转手卖给其他有需要的人,这就是中间商。他们控制这生产商(request)的产品来源,同时也有大量的终端客户(response),而他们做的是中间连接的一个过程,或者能高价卖出,先爽一把;或者薄利多销,扩大市场影响(这些都是中间过程会发生的事)。那我们现在依赖koa做的就是这个中间商的事。
听完了我家乡中间商的故事,我们回到现实生活中,看看我们有了货源的保障(request)和终端客户(response),我们作为程序中的中间商能做点什么呢?好的,我先拿个小生意跟大家分享一下。
简单的例子
// app.js
const Koa = require('koa')
const app = new Koa()
// 中间过程处理数据,输出结果
app.use((ctx, next) => {
const str = 'hello world'
ctx.body = str
})
// 绑定端口3000
app.listen(3000)
接下来我们需要执行命令node app
就将一个web服务器搭建好了,然后在浏览器上输入localhost:3000
就能在页面上看到hello world
的文字。前面的const Koa = require('koa');const app = new Koa()
和后面的app.listen(3000)
都是搭建web服务器建立连接必须要的,是固定的写法。这两个步骤可以看成是request接口成功。然后ctx.body = str
属于输出response的过程,app.use((ctx, next) => {const str = 'hello world';})
就属于中间件的处理过程。这个中间环节也很简单,就是定义了一个变量str
,然后就是没了,只做了这样一件事。然后response把中间环节做得事的结果输出,我们就看到了在本地,端口是3000的服务器中看到了hello world
。
而koa又设计的非常简单,如上面的这个例子所示,几行代码就完成了服务器建立并返回的事。如果我们要做更复杂一点的事情,就需要依赖于其他的中间件来完成。这个跟vue也有点类似:你看,vue只是提供了MVVM的模型,你如果还要做页面路由就要跟VueRouter说一句:“姐姐,帮帮我把页面路由搞定吧(没办法,代码敲多了看谁都像姐姐)”,如果要做全局的数据管理还要跟Vuex说一句:“哥哥,帮我做一下数据管理吧”。
而koa似乎也很懂这一套。
当他要获取服务器静态资源的时候,他就会跟KoaStaticCache打声招呼:小姐姐,帮我读取一下静态文件,等会有好吃的给你;当他要读取接口时,会跟KoaRouter说一句:小哥哥,帮我读取一下路由啊,等会帮你上分;当他要读取post请求数据时,会跟KoaBodyparser说一句:阿姨,那个请求是post,麻烦你帮我拿一下他的请求数据吧。所以大多数时候,在使用koa的同时,下面这些插件也常常会出现:
- koa-static-cache:静态文件代理服务
- koa-router:路由
- koa-swig:模板引擎
- koa-bodyparser:post请求的body参数解析
有了前面的这些基础,可以进入项目了。
在这个项目中涉及到上面知识点的就只有server/app.js
和server/routes/main.js
这两个文件。是不是超级简单,就问你是不是?
好那我们来解析这两个文件做了什么?
解读项目文件
app.js
// 这部分是将上面提到的几个插件引入
const Koa = require('koa')
const KoaStaticCache = require('koa-static-cache')
const bodyParser = require('koa-body-parser')
const router = require('./routes/main')
const app = new Koa()
// 读取服务器中的静态文件,例如css,图片等内容
app.use(KoaStaticCache(__dirname + '/static', {
prefix: '/static',
maxAge: false,
gzip: true
})
)
// 对post请求的解析
app.use(bodyParser({}))
// 将路由挂载到app上
app.use(router.routes())
app.listen(3000)
第一个要说的是app.use(KoaStaticCache(...))
这个方法。这是读取服务器中静态文件的方法。静态文件指的是比如css、图片等资源。这里的配置指的是静态文件在当前文件夹下的static,不使用缓存,使用gzip压缩。但是我这个gua64项目里没有引入静态文件(目的是为了教大家怎么用这个)。
第二个要说的是app.use(bodyParser({}))
,app.use的意思是使用该中间件。执行该语句之后,就能在ctx.request.body中找到对应的入参了。同样我在这个demo中没有用到post请求,写出来是为了演示这个东西怎么用。
第三个要说的是app.use(router.routes())
,我把所有的路由都放在了server/routes/main.js
文件中,这里的路由其实就是我们常说的接口。接口不就是一个有映射关系的地址嘛。具体的接口信息我们看main.js
,前面的这些都是固定写法 + 配置,看看官方文档很快就能动手操刀了。
main.js
// 查询内容接口
router.get('/findContent', async ctx => {
const searchName = ctx.query.searchName || ''
// 查找包含某个字段的数据
let {count, rows} = await Models.Contents.findAndCountAll({
where: {
[Op.or]: [
{
name: {
[Op.like]: `%${searchName}%`
}
},{
desc: {
[Op.like]: `%${searchName}%`
}
}
]
},
})
ctx.body = {
code: 0,
count: count,
data: rows.map(item => {
return {
id: item.id,
contentId: item.contentId,
name: item.name,
contentList: item.contentList,
desc: item.desc,
likeCount: item.likeCount
}
})
}
})
看一下上面的查询内容接口。是不是跟我前面写的简单的例子一毛一样?这里的中间环节就是去数据库中找到对应条件的内容,也就是这里的变量count
和rows
,拿到了之后按照前端要的数据格式返回出去,然后就没了。简单到爆炸。
至于怎么查询数据库中的内容我们放在下节课来讲,这不是这节课的重点。
总结
我们开始先了解了koa是什么东西,然后用水池的例子跟大家类比了一下koa做了什么,我们依赖于koa能做什么,并且相互协作让整个服务跑起来。然后我用一个很简单的例子演示了一下怎么使用koa这个东西。最后我把项目中用到koa的部分单独拎出来分析,发现他在项目中的使用和我那个例子也是惊人的相识。所以,我个人认为koa最关键的点是在app.use()函数中对于数据处理的这部分内容,拿到了这部分内容返回给前端,就完了。
下一篇我们将对sequelize和sequelize-cli的使用做一个分析。
另外我自己新建了一个QQ群,群号码是:1103713567(全栈开发跳板群)。方便大家一起交流前端方面或者项目方面的问题。