Koa 入门 -->搭建项目 --> 源码解析 --> 手写源码(二)

102 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第26天,点击查看活动详情

搭建项目

新建 app.js

const Koa = require('koa')

const app = new Koa()

app.use(async (ctx, next) => {
    ctx.body = 'hello Koa'
})

app.listen(3000)

地址栏输入 localhost:3000

app.js

const Koa = require('koa')
const Router = require('koa-router')

const app = new Koa()
const router = new Router()

app.use(async (ctx, next) => {
    ctx.body = 'hello Koa'
    await next()
})

router.get('/test', async (ctx) => {
    ctx.body = 'hello koa-router'
})

app.use(router.routes()).use(router.allowedMethods())

app.listen(3000)

访问 localhost:3000/test 就可以看到 hello koa-router

项目不可能所有的接口都放在主文件里面,所以在 routes 新建两个文件夹 user, news,里面新建两个文件 user/admin.js , news/list.js

app.js

const Koa = require('koa')
const Router = require('koa-router')
// 引入两个文件
var admin = require('./routes/user/admin.js')
var newList = require('./routes/news/list.js')

const app = new Koa()
const router = new Router()

router.get('/', (ctx) => {
    ctx.body = 'home page'
})

// 配置这两个,当你访问 /admin 这个路由是,会转发的 admin.js 文件下
router.use('/admin', admin.routes())
router.use('/news', newList.routes())

app.use(router.routes()).use(router.allowedMethods())

app.listen(3000)

routes/user/admin.js

const router = require('koa-router')()

router.get('/user', (ctx) => {
    ctx.body = 'admin'
})

module.exports = router

localhost:300/admin/user

动态匹配路由

const router = require('koa-router')()

router.get('/user', (ctx) => {
    ctx.body = 'admin'
})

router.get('/add/:id/:bid', async (ctx) => {
    console.log(ctx.params)
    // { id: '112', bid: 'qwe' }
    ctx.body = '添加详情'
})

module.exports = router

localhost:3000/add/112/qwe

get 请求之后,就是 post 请求

const Koa = require('koa')
const Router = require('koa-router')
// 引入
var bodyParser = require('koa-bodyparser')
var admin = require('./routes/user/admin.js')
var newList = require('./routes/news/list.js')

const app = new Koa()
const router = new Router()

// 使用
app.use(bodyParser())

router.get('/', (ctx) => {
    ctx.body = 'home page'
})

router.use('/admin', admin.routes())
router.use('/news', newList.routes())

app.use(router.routes()).use(router.allowedMethods())

app.listen(3000)

routes/news/list.js

const router = require('koa-router')()

router.get('/list', (ctx) => {
    ctx.body = 'list'
})

router.post('/postRoute', async (ctx, next) => {
    const rb = ctx.request.body
    console.log(rb);
    ctx.response.body = 'success'
})

module.exports = router

post 在浏览器的地址栏里面直接输入是不可以的,可以使用 postman 来进行测试。

在这里插入图片描述

{ user: 'mjhgf', age: '111', sex: '0' }

操作数据库

npm install mongodb --save

根目录下新建一个utils文件夹, 里面放上 config.js, db.js

config.js

const app = {
    dbUrl: 'mongodb://localhost:27017',
    dbName: 'koa'
}

module.exports = app

db.js(对MongoDB的封装)

const MongoClient = require('mongodb').MongoClient
const ObjectID = require('mongodb').ObjectID
const Config = require('./config.js')

class Db {
  // 单例模式
  static getInstance() {
    if (!Db.instance) {
      Db.instance = new Db()
    }
    return Db.instance
  }

  constructor() {
    this.dbClient = ''
    this.connect()
  }

  connect() {
    return new Promise((resolve, reject) => {
      if (!this.dbClient) {
        MongoClient.connect(Config.dbUrl, { useUnifiedTopology: true }, (err, client) => {
          if (err) {
            reject(err)
          } else {
            const db = client.db(Config.dbName)
            this.dbClient = db
            resolve(this.dbClient)
          }
        })
      } else {
        resolve(this.dbClient)
      }
    })
  }

  find(collectionName, json) {
    return new Promise((resolve, reject) => {
      this.connect().then(function (db) {
        const result = db.collection(collectionName).find(json)
        result.toArray(function (err, docs) {
          if (err) {
            reject(err)
            return
          } else {
            resolve(docs)
          }
        })
      })
    })
  }

  update(collectionName, json1, json2) {
    return new Promise((resolve, reject) => {
      this.connect().then((db) => {
        db.collection(collectionName).updateOne(json1, {
          $set: json2
        }, (err, result) => {
          if (err) {
            reject(err)
            return
          } else {
            resolve(result)
          }
        })
      })
    })
  }

  insert(collectionName, json) {
    return new Promise((resolve, reject) => {
      this.connect().then((db) => {
        db.collection(collectionName).insertOne(json, function (err, result) {
          if (err) {
            reject(err)
            return
          } else {
            resolve(result)
          }
        })
      })
    })
  }

  remove(collectionName, json) {
    return new Promise((resolve, reject) => {
      this.connect().then((db) => {
        db.collection(collectionName).removeOne(json, function (err, result) {
          if (err) {
            reject(err)
            return
          } else {
            resolve(result)
          }
        })
      })
    })
  }

  // 查询 _id
  getObjectID(id) {
    return new ObjectID(id)
  }
}

module.exports = Db.getInstance()

routes/user/admin.js (连接自己的数据库,在数据库中新建一个 koa 数据库,新建一个user表)

const router = require('koa-router')()
const DB = require('../../utils/db.js')

router.get('/user', async (ctx) => {
    var result = await DB.find('user', {})
    ctx.body = result
})

module.exports = router

这样就可以使用 koa 操作数据库了。

数据库增删改查

routes/user/admin.js

const router = require('koa-router')()
const DB = require('../../utils/db.js')

router.get('/add/:id/:bid', async (ctx) => {
    // http://localhost:3000/add/112/qwe
    console.log(ctx.params)
    // { id: '112', bid: 'qwe' }
    ctx.body = '添加详情'
})

// 查询
router.get('/list', async (ctx) => {
    var result = await DB.find('user', {})
    ctx.body = result
})

// 插入
router.post('/doAdd', async (ctx) => {
    let data = await DB.insert('user', ctx.request.body)
    ctx.body = data
    try {
        if (data.result.ok) {
            console.log(ctx.body)
        }
    } catch (error) {
        console.log(err)
        ctx.redirect('/')
    }
})

// 删除
router.get('/remove', async (ctx) => {
    // let user = ctx.query.user
    let user = ctx.request.body.user
    console.log(user)
    var data = await DB.remove('user', {'user': user})
    try {
        if (data.result.ok) {
            // ctx.redirect('/')
            ctx.body = data
        }
    } catch (error) {
        console.log(err)
    }
})

// 更新
router.get('/update', async (ctx) => {
    var id = ctx.query.id
    var user = ctx.query.user
    var age = ctx.query.age
    var sex = ctx.query.sex

    console.log(DB.getObjectID(id), user, age, sex)

    let data = await DB.update('user', {'_id': DB.getObjectID(id)}, {
        age,
        sex
    })

    try {
        if (data.result.ok) {
            ctx.body = data
        }
    } catch (error) {
        console.log(err)
        ctx.redirect('/add')
    }
})


module.exports = router

登录和注册功能

新建 login.js

const router = require('koa-router')()
const DB = require('../../utils/db.js')

router.post('/register', async (ctx) => {
    let data = await DB.insert('author', ctx.request.body)
    console.log(data)
    ctx.body = data
    try {
        if (data.result.ok) {
            ctx.redirect('/login/getInfo')
        }
    } catch (error) {
        console.log(error)
        // ctx.redirect('/')
    }
})

router.post('/login', async (ctx) => {
    let name = ctx.request.body.name
    let email = ctx.request.body.email
    let pwd = ctx.request.body.pwd

    console.log(name, email, pwd)
    var result = await DB.find('author',
    {'name': name, 'email': email, 'pwd': pwd})

    console.log(result)
    try {
        if (result.length > 0) {
            ctx.body = '登录成功'
            ctx.redirect('/')
        }
    } catch (error) {
        console.log(error)
        // ctx.redirect('/')
    }
})

router.get('/getInfo', async (ctx) => {
    var result = await DB.find('author', {})
    ctx.body = result
})

module.exports = router

利用 JWT 设置 Token

const Koa = require('koa')
const Router = require('koa-router')
const bodyParser = require('koa-bodyparser')
const jwt = require('jsonwebtoken')
const jwtKoa = require('koa-jwt')

var admin = require('./routes/user/admin.js')
var newList = require('./routes/news/list.js')
var login = require('./routes/user/login.js')
const DB = require('./utils/db.js')
const keys = require('./utils/config')

const app = new Koa()
const router = new Router()

const secret = 'secret'

app.use(jwtKoa({secret}).unless({
    path: [/\/register/, /\/login/]
}))

app.use(bodyParser())

app.use(async (ctx, next) => {
    console.log(ctx)
    let params = Object.assign({}, ctx.request.query, ctx.request.body);
    ctx.request.header = {'authorization': "Bearer " + (params.token || '')}
    await next();
})

router.get('/', async (ctx) => {
    ctx.body = 'home'
})

router.post('/register', async (ctx) => {

    console.log(ctx.request.body.email)
    let email = ctx.request.body.email

    const findResult = await DB.find('author', {
        'email': email
    })

    console.log(findResult)

    if (findResult.length > 0) {
        ctx.status = 506
        ctx.body = { email: '邮箱已被占用 ' }
    } else {
        let data = await DB.insert('author', ctx.request.body)
        console.log(data)
        ctx.body = data
        try {
            if (data.result.ok) {
                ctx.body = {
                    mssage: '注册成功'
                }
            }
        } catch (error) {
            console.log(error)
            // ctx.redirect('/')
        }
    }
})

router.post('/login', async (ctx, next) => {
    let name = ctx.request.body.name
    let email = ctx.request.body.email
    let pwd = ctx.request.body.pwd

    console.log(name, email, pwd)

    var result = await DB.find('author',
    {'name': name, 'email': email})

    console.log(result)

    if (result.length === 0) {
        ctx.status = 404
        ctx.body = { email: '用户不存在!' }
    } else {
        var result = await DB.find('author',{'pwd': pwd})
        if (result) {
            // 返回token
            const payload = { pwd: pwd, name: name}
            const token = jwt.sign(payload, keys.secretOrkey, { expiresIn: 3600 })

            ctx.status = 200
            ctx.body = { success: true, token: 'Bearer ' + token }
        } else {
            ctx.status = 400
            ctx.body = { password: '密码错误!' }
        }
    }
})

router.use('/admin', admin.routes())
router.use('/news', newList.routes())
router.use('/login', login.routes())

app.use(router.routes()).use(router.allowedMethods())

app.listen(3000)

之后,项目需要什么接口,就向 routes 中添加对应的接口。

项目地址:gitee.com/suiboyu/koa…