koa2+mongodb搭建後臺


title: koa2+mongodb搭建後臺
date: 2018-12-28
categories:html

  • frontend
    tags:
  • koa2
  • mongodb
  • nodejs

前言

毫無疑問,目前nodejs裏面用來開發後臺的首選就是koa2+mongodb的組合了。參考過不少資料,都是零零碎碎不齊全,要麼很簡單只是教你如何運行一個demo,要麼只講了簡單的一方面,要麼就是一個複雜的koa項目生成器,我設想的一個最基礎的後臺應該具備如下內容:node

此處只討論先後端分離,後臺項目提供接口,不考慮模板渲染之類的,畢竟你都用nodejs作後臺了,還不作先後端分離也太說不過去了mongodb

  • 對傳入、返回及錯誤數據作統一處理
  • 支持跨域
  • 使用 token 作身份驗證
  • 完善的日誌記錄
  • 支持發送郵件
  • 上傳文件
  • 常見的數據庫操做,對列表數據分頁,返回指定行數據作封裝
  • 調試

因此在折騰完以後,就想把整個過程記錄一下,若是你正好是剛開始摸索,應該能讓你避免很多彎路。chrome

建立基礎項目

  • 建立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啓動一個項目就是這麼簡單。。npm

添加路由

在koa-router的使用說明中,咱們能夠看到是這樣使用的:json

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:api

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

待續

日誌模塊

待續

微信支付

待續

相關文章
相關標籤/搜索