koa2+mongodb搭建后台

前言

毫无疑问,目前nodejs里面用来开发后台的首选就是koa2+mongodb的组合了。参考过很多资料,都是零零碎碎不齐全,要么很简单只是教你如何运行一个demo,要么只讲了简单的一方面,要么就是一个复杂的koa项目生成器,我设想的一个最基础的后台应该具有以下内容:

此处只讨论前后端分离,后台项目提供接口,不考虑模板渲染之类的,毕竟你都用nodejs做后台了,还不做前后端分离也太说不过去了

  • 对传入、返回及错误数据做统一处理
  • 支持跨域
  • 使用 token 做身份验证
  • 完善的日志记录
  • 支持发送邮件
  • 上传文件
  • 常见的数据库操作,对列表数据分页,返回指定行数据做封装
  • 调试

所以在折腾完之后,就想把整个过程记录一下,如果你正好是刚开始摸索,应该能让你避免不少弯路。

创建基础项目

  • 创建koa-mongo目录,并运行 npm init 创建package.json
mkdir koa-mongo
cd ./koa-mongo
npm init
  • 安装基础包
npm install koa # koa,必须的
npm install koa-router  # 路由,必须的,这里要注意的是还有一个koa-route,这两个是不同的,不要用koa-route
npm install koa-static  # 静态资源,必须的
  • 创建app.js,填入以下内容:
// koa
const Koa = require('koa')
const app = new Koa()

// midleware
const serve = require('koa-static')

app.use(serve('./assets'))

var server = app.listen(3000, function (){
    const host = server.address().address;
    const port = server.address().port;
    console.log('app start listening at http://%s:%s', host, port);
});

此处创建了一个实例,监听3000端口,将assets目录作为静态资源运行,我们创建一个assets目录,里面创建一个index.html,然后我们运行起来试试:

node ./app.js

此时会打印一行日志:app start listening at http://:::3000,让我们来访问试试:

ok,koa启动一个项目就是这么简单。。

添加路由

在koa-router的使用说明中,我们可以看到是这样使用的:

var router = new Router();
 
router.get('/', (ctx, next) => {
  // ctx.router available
});
 
app
  .use(router.routes())
  .use(router.allowedMethods());

因为正常项目中,controller肯定不止一个的,所以我把目录写成这样:

├─ controller
    ├─ test-controller
├─ router.js

controller目录用来放置所有的controller,在router.js中统一汇总,app.js中只需要使用router.js即可。
test-controller:

const hello = async (ctx, next) => {
    ctx.body = 'hello world'
    ctx.status = 200;
}

module.exports = {
    'test/hello': hello,
}

router.js:

const Router = require('koa-router')
const router = new Router({
    prefix: '/api', // 统一前缀,接口全部为 /api/xxx 格式
})

const testController = require('../controller/test-controller')

Object.keys(testController).forEach(key=>{
    router.all("/"+key, testController[key]);   // router.all是允许所有的访问方式,如果需要限定则改为指定方式即可
})

module.exports = router;

app.js:

// router
const router = require('./router')
app.use(router.routes()).use(router.allowedMethods())

这个时候让我们重新启动一下,访问localhost:3000/api/test/hello试试:

可以看到正确返回了hello world。

调试

到这里了,有没有感觉哪里不对劲。每修改一次,都需要手动敲命令重启一次,这简直太烦了好嘛,我们程序猿哪能忍受这个。答案就是使用nodemon,这个玩意儿能监听我们的文件变更,自动运行命令重启应用。使用方式也很简单,这个我们直接全局安装就好了:

npm install -g nodemon

然后去package.json的scripts中添加一行脚本:

"dev": "nodemon ./app.js",

然后 npm run dev,把hello函数修改一下返回值,保存,就会看到nodemon自动帮我们重启应用了。

除了nodemon,类似的工具还有很多,这里就不展开说了,现在的你只需要知道开发用nodemon,线上用pm2就ok了

解决了自动运行之后,我们来说一下调试。其实nodejs自带了调试的,只需要一个inspect参数,调试的时候就跟我们在chrome中调试是一模一样的。
我们先去package.json的scripts中添加一行脚本:

"debug": "nodemon --inspect ./app.js",

然后我们运行 npm run debug,刷新我们的网页,用f12打开,此时我们能看到开发者工具上面多了一个nodejs的图标:

点击这个图标,就可以跟调试网页一样调试nodejs代码了:

配置化

代码就是一步步总结,边写边优化,重构。到目前为止,我们会发现有不少配置性的东西是散乱在不同文件中,比如说项目启动时监听的端口,接口的统一前缀,考虑到我们还会有很多配置项,我们应该把这些写到一个配置文件中集中管理。
新建一个config.js:

module.exports= {
    port: 3000,
    apiPrefix: '/api',
}

然后把用到的地方全部更改为变量

跨域

为了防止跨域问题,我们需要使用koa2-cors类库,使用方式很简单:

npm install koa2-cors

然后在app.js中添加以下内容:

const cors = require('koa2-cors')
app.use(cors())

一行代码搞定,cors的具体配置此处就不细说了,有兴趣的可以自己去看看

处理参数,上传文件

一般来说,我们是使用koa-bodyparser 和 koa-multer来分别处理表单数据和文件数据的。这两个分别集成也没什么问题,但我们可以直接使用koa-body来完成。koa-body是基于co-body和formidable做了封装,同时支持参数解析和文件上传。最后是把参数和文件分别放到ctx.request.body和ctx.request.files变量中。
我这里是把上传文件统一放到assets/upload目录中:

const uploadDir = path.join(__dirname, 'assets/upload/')
// 此处还需要判断文件夹是否存在,不存在的话就创建
app.use(koaBody({
    multipart: true,
    encoding: 'utf-8',
    formidable:{
        uploadDir: uploadDir,
        keepExtensions: true,
        maxFieldsSize: 5*1024*1024,
        onFileBegin:(name, file)=>{

        }
    }
}))

然后添加一个upload:

const upload = async (ctx, next)=>{
   const files = ctx.request.files || {};   # 文件会被解析到ctx.request.files中,是个object
   let fileNames = Object.keys(files);
   if(fileNames.length<=0){
       throw new ApiError('上传文件不能为空')
   }else{
       if(fileNames.length===1){
           ctx.body = files[fileNames[0]].path.replace(config.baseDir+'/assets', "")
       }else {
           ctx.body = fileNames.map(key => files[key].path.replace(config.baseDir+'/assets', ""))
       }
   }
}

token验证

使用jwt,待续

统一返回格式

待续

mongodb

待续

日志模块

待续

微信支付

待续

posted @ 2018-12-28 19:50  Thyiad  阅读(5296)  评论(5编辑  收藏  举报