koa2+mongodb搭建后台



title: koa2+mongodb搭建后台
date: 2018-12-28
categories:

  • frontend
    tags:
  • koa2
  • mongodb
  • nodejs

前言

毫無疑問,目前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

待續

日志模塊

待續

微信支付

待續


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM