Koa2 + Mongodb(從0到1)搭建項目
一、前言
雖然,對于新手來說,我們選擇類似于koa-generator之類的腳手架,可以最快的入手koa2或者node項目。但是,自己搭建項目,更加適用于實際開發(fā)中前后端分離的定制化業(yè)務(wù)場景,且能讓我們不僅僅關(guān)注于開發(fā)本身,知其然知其所以然,收獲更多的東西。
在全局中安裝koa依賴包 (保持項目版本的統(tǒng)一性)或在本地項目中安裝
npm install -g koa
npm install koa --save
二、創(chuàng)建項目 & 安裝依賴
1、創(chuàng)建文件且初始化項目
npm init
2、安裝依賴
// 路由
npm install koa-router koa-bodyparser --save
// 熱重啟
npm install nodemon --save
// 支持import模塊的引入
npm install babel-plugin-transform-es2015-modules-commonjs babel-register --save
// mongodb
npm install mongoose --save
// 解決跨域問題
npm install koa2-cors --save
三、配置
1、基礎(chǔ)配置
最基本的開發(fā)環(huán)境已搭建完,開啟service監(jiān)聽3000端口:
對于任何請求,app將調(diào)用異步函數(shù)
app.use(async (ctx, next) => {})處理請求,只有當(dāng)next()之后才能執(zhí)行下一個app.use()
const Koa = require('koa')
const app = new Koa({
// 代理
// proxy: true
});
// logger
app.use(async (ctx, next) => {
console.log('--0-0--')
await next();
const rt = ctx.response.get('X-Response-Time')
console.log(`--0-1-- ${ctx.method} ${ctx.url} - ${rt}`)
})
// x-response-time
app.use(async (ctx, next) => {
console.log('--1-0--')
const start = new Date()
await next()
const ms = Date.now() - start;
console.log('--1-1--')
ctx.set('X-Response-Time', `${ms}ms`);
})
// response
app.use(async ctx => {
ctx.body = 'Hello World, Koa!'
})
app.listen(3000)
2、配置路由
const Koa = require('koa');
const bodyParser = require('koa-bodyparser');
const app = new Koa();
app.use(bodyParser()); // 解析request的body
const router = require('koa-router')()
router.get('/', async (ctx, next) => {
// todo
})
app.use(router.routes());
app.listen(3000);
console.log('app started at port 3000...')
可直接訪問端口3000,若針對BFF層開發(fā)聚合接口,可增加api前綴標(biāo)識
const Router = require('koa-router')
const router = new Router({
prefix: '/api'
})
此時訪問地址變?yōu)椋?code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(60, 112, 198);">http://localhost:3000/api
3、熱重啟處理
對標(biāo)webpack項目中的熱更新,代碼的修改,不必重新npm run start啟動項目就可以實時的看到效果。對于node項目的管理,當(dāng)然也有類似的工具:nodemon
Nodemon,用于監(jiān)視源中的任何更改并自動重新啟動服務(wù)器。支持自定義配置
nodemon.json使用
更改package.json,執(zhí)行 npm run start,達(dá)到了熱重啟的效果
// package.json
"scripts": {
...
"start": "nodemon app.js"
},
4、node 支持 import模塊引入(可忽略)
原生的
node不支持import引入模塊,所以項目中強(qiáng)行使用import方式引入,會拋出類似報錯信息:SyntaxError: Unexpected token import
解決方案涉及按如下幾個方面:
安裝 babel依賴根目錄下創(chuàng)建 start.js更改 package.json
安裝如下依賴
npm install babel-plugin-transform-es2015-modules-commonjs babel-register --save
根目錄下創(chuàng)建start.js
require('babel-register')
(
{
plugins: ['babel-plugin-transform-es2015-modules-commonjs'],
}
)
module.exports = require('./app.js')
更改 package.json
"scripts": {
...
"start": "nodemon star.js"
}
完成以上三個步驟,在app.js內(nèi)使用import語法,運行 npm start,剛才報錯信息消失
5、連接數(shù)據(jù)庫
安裝: npm install mongoose --save啟動: mongod視圖管理: MongoDB Compass
a. 搭建如下數(shù)據(jù)庫:

b. 查詢語句
// 文件路徑: app/dbHelper/user.js
const MongoClient = require('mongodb').MongoClient;
const assert = require('assert');
// mongoDB
const dbUrl = "mongodb://localhost:27017/testLocal";
const client = new MongoClient(dbUrl, {useNewUrlParser: true});
const dbName = 'testLocal'
const tableName = 'user'
/**
* @desc: 查詢所有用戶
*/
exports.queryUsers = function() {
return new Promise(function (resolve, reject) {
try {
client.connect(function(err) {
assert.equal(null, err);
const db = client.db(dbName);
const collection = db.collection(tableName);
collection.find({}).toArray(function(err, result) {
assert.equal(err, null);
// console.log('--db-1-result--', result)
client.close();
resolve(result)
});
})
} catch(e) {
reject(e)
}
})
}
c. 運行程序查看結(jié)果
數(shù)據(jù)查詢結(jié)果:

視圖結(jié)果:

到此為止,聚個BFF層接口功能的項目結(jié)構(gòu)基本就滿足了。
6、解決跨域
對于接口跨域,解決的辦法有很多,jsonp、cros、Nginx代理、node代理等。這里只介紹cros方案:koa2-cors
入口文件
// app.js 引入
const cors = require('koa2-cors')
const app = new Koa()
import corsConfigs from './configs/cors'
// 處理跨域的配置
app.use(cors(corsConfigs));
配置文件
// config/cors.js
/**
* @desc: 跨域處理配置項
* @author: lianpf
* @date: 2021-02-24
* */
const corsConfigs = {
exposeHeaders: ['WWW-Authenticate', 'Server-Authorization', 'Date'],
maxAge: 100,
credentials: true,
allowMethods: ['GET', 'POST', 'OPTIONS'],
allowHeaders: ['Content-Type', 'Authorization', 'Accept', 'X-Custom-Header', 'anonymous'],
}
export default corsConfigs
四、TS & ESLint
待補(bǔ)充...
可收藏 曜靈(SUN)SITE ??,及時獲取文章更新信息
五、Project 結(jié)構(gòu)圖
├── app
│ ├── controller
│ │ └── user.js
│ ├── dbHelper
│ │ └── user.js
│ └── router.js
├── app.js
├── configs
│ └── cors.js
├── package-lock.json
├── package.json
└── start.js
源碼參考
gitHub倉庫
關(guān)鍵文件
app.js
/**
* @desc: 入口文件
* @author: lianpf
* @date: 2021-02-24
* */
const Koa = require('koa');
const bodyParser = require('koa-bodyparser')
const cors = require('koa2-cors')
const app = new Koa()
import router from './app/router'
import corsConfigs from './configs/cors'
// 處理跨域的配置
app.use(cors(corsConfigs));
// logger 中間件
// const loggerAsync = require('./middleware/logger-async')
// app.use(loggerAsync())
// router
app.use(bodyParser()); // 解析request的body
app.use(router.routes());
// response
// app.use(async ctx => {
// ctx.body = 'Hello World, Koa!'
// })
// 在端口3000監(jiān)聽:
app.listen(3000);
console.log('app started at port 3000...')
package.json
{
"name": "koa2-ts-mongodb",
"version": "1.0.0",
"description": "koa2-mongodb-ts demo",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon start.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
"babel-register": "^6.26.0",
"koa": "^2.13.1",
"koa-bodyparser": "^4.3.0",
"koa-router": "^10.0.0",
"koa2-cors": "^2.0.6",
"mongoose": "^5.11.18",
"nodemon": "^2.0.7"
},
"devDependencies": {
"@types/koa": "^2.13.0",
"tslint": "^6.1.3",
"typescript": "^4.1.5"
}
}
start.js
require('babel-register')
(
{
plugins: ['babel-plugin-transform-es2015-modules-commonjs'],
}
)
module.exports = require('./app.js')
app/router.js
const router = require('koa-router')()
const User = require('./controller/user')
router.get('/', User.query)
export default router1.看到這里了就點個在看支持下吧,你的「點贊,在看」是我創(chuàng)作的動力。
2.關(guān)注公眾號
程序員成長指北,回復(fù)「1」加入高級前端交流群!「在這里有好多 前端 開發(fā)者,會討論 前端 Node 知識,互相學(xué)習(xí)」!3.也可添加微信【ikoala520】,一起成長。
“在看轉(zhuǎn)發(fā)”是最大的支持
