koa2 快速上手

1.koa2简介:

koa2是由express原开发人员开发的,是为了解决Express处理异步回调嵌套过深的问题的node服务端开发框架,最初是第一版被称为koa,koa存在Generator+yield不太好的地方,后来就出现第二版koa2,koa2中支持async/await,但是我express项目中也是在用async/await。

2.koa2特点:

支持async/await语法糖、支持洋葱模型的中间件。

洋葱模型中间件:web服务器在处理一个又一个的请求并作出响应时,在这个过程中需要程序处理,这个处理的程序被称为中间件,多个中间件在处理的过程中是由外到内,在由内到外的过程,从请求到响应可以理解为竹签穿过洋葱,洋葱每层表示一个中间件。

3.koa2快速上手:

1.安装koa2:npm install koa,下载时无需写koa2,下载时会自动下koa2。

2.创建koa对象,编写响应函数(中间件)

3.监听端口,启动程序,具体如下代码:

const koa = require('koa')
// 创建koa对象
const app = new koa()
// 挂载中间件:(中间件实际就是一个处理并返回结果的函数,可能你不需要写return,但是ctx中也是会返回数据),实际开发中会将中间件抽离到单独的文件中,之后挂载到app上
app.use((ctx,next) => {
    
    
  // ctx表示上下文,可以调用到请求对象和响应对象,next表示下一个中间件的执行
  console.log(ctx.request.url)
  // 设置响应体:
  ctx.response.body = 'hello word!'
  // 调用下一中间件执行: (从上到下一次执行中间件,但是是在调用next的情况下才会执行)
  console.log('第一层中间件1')
  next()
  console.log('第一层中间件2')
  return '第一层'
})
// 又一层中间件:
app.use((ctx, next) => {
    
    
  console.log('第二层中间件1')
  next()
  console.log('第二层中间件2')
  return '第二层'
})
  // 执行顺序:第一层中间件1-------第二层中间件1---------第二层中间件2--------第二层中间件1,洋葱模型,从外到里,在从内到外

// 监听服务启动:
app.listen(3000)

4.项目中使用koa:

本项目也是一个demo,实际中可能有很多种处理中间件,在这里我我使用三个中间件处理数据,分别是计算耗时中间件、设置响应头中间件、处理业务中间件(登录接口实现)

总耗时中间件:

module.exports = async (ctx, next) => {
    
    
  // 每次请求先记录一次时间:
  const start = Date.now()
  // 让内层中间件执行,此过程会耗时,内层中间件执行完后,下面的代码才会执行,所以在next后面再次获取当前时间,之后做减法就是总耗时
  await next()//通常情况下中间件中有异步,所以这里使用async/await
  const end = Date.now()
  const totalTime = end - start
  // 将总耗时设置给响应头:
  ctx.set('X-Response-Time', totalTime + 'ms')
}

设置响应头中间件:

module.exports = async (ctx, next) => {
    
    
  // 统一设置响应数据类型为:json格式
  const contentType = 'application/json; charset=utf-8'
  ctx.set('Content-Type', contentType)
  // 解决跨域:
  ctx.set('Access-Control-Allow-Origin','*')
  ctx.set('Access-Control-Allow-Methods','OPTIONS, GET, PUT, POST, DELETE')
  await next()
}

app.js入口文件:

// 引入计算总耗时的中间件:
const duiringTime = require('./middleware/duringtime')
// 引入设置响应头的中间件:
const setResponseHeader = require('./middleware/setresponseheader')
// 引入解析请求体的中间件:koa-bodyparser
const bodyParser = require('koa-bodyparser')
// 导入登录路由
const loginserve = require('./serves/loginserve')

const Koa = require('koa')
// 创建Koa实例对象:
const app = new Koa()

// 绑定计算耗时的中间件:
app.use(duiringTime)
// 挂载设置响应头的中间件:
app.use(setResponseHeader)
// 挂载bkoa-bodyparser中间件:如果不配置的话在路由页就不能通过ctx.request.body拿到请求体
app.use(bodyParser())

// 挂载登录接口路由:
app.use(loginserve.routes())

// 绑定端口号:
app.listen(3000,() => {
    
    
  console.log('serve is running at 3000!')
})

loginserve登录接口文件:

// 引入路由模块:
const Router = require('koa-router')
// 引入数据库配置
const connection = require('../config/mysqldbconfig')
//引入token工具
const {
    
    createToken} = require('../commethods/creattoken')
// 创建路由实例:
const router = new Router({
    
    prefix:'/api'})//里面可接收一个对象,可以设置些默认配置,如{prefix:'/api'}设置路由匹配前缀

// 实现一个登录接口:
// 在创建路由时默认加了前缀 /api ,下面router.post('/login', ()=>{})可直接匹配:'/api/login'路由
router.post('/login',async (ctx, next) => {
    
    
  let {
    
    userName, userPassword} = ctx.request.body
  let sql = 'SELECT `user_password`,`user_id`,`user_name` FROM theuser WHERE user_name = "'+userName+'"'
  // 这里不能像express中直接对数据库进行操作,否则响应拿不到查询结果,这里必须使用异步,将查询封装到一个异步函数中,之后在这里使用await调用封装的函数,如:
  // 封装查询函数(可以抽离到单独的文件中):
  function isLogin (sql){
    
    
    return new Promise((resolve,reject) => {
    
    
      connection.query(sql,(error, result) => {
    
    
        if (error) {
    
    
          reject()
        } else {
    
    
          resolve(result)
        }
      })
    })
  }
  // 调用查询函数
  let results = await isLogin(sql)
  // 响应:用户名存在时:
  if (results.length > 0) {
    
    
    // 且密码正确时:
    if (results[0].user_password === userPassword) {
    
    
      // 生成token规则
      let rule = {
    
    id:results[0].user_id,naems:results[0].user_name}
      // 生成token并响应:
      let token = createToken(rule)
      ctx.body = {
    
    cod: 200, msg: '登录成功!', userId: results[0].user_id, token: token}
    } else {
    
    
      ctx.body = {
    
    cod: 201, msg: '密码错误!'}
    }
  }  else {
    
    
    // 用户名不存在时:
    ctx.body ={
    
    cod: 202, msg: '用户不存在!'}
  }

  // 经测试,直接return一个Promise也可以在响应时拿到结果,查阅资料都是以上方式实现的
  return new Promise((resolve,reject) => {
    
    
    connection.query(sql, (error, results) => {
    
    
      try {
    
    
        if (error) {
    
    
          throw error
        } else {
    
    
          // 用户名存在时:
          if (results.length > 0) {
    
    
            // 且密码正确时:
            if (results[0].user_password === userPassword) {
    
    
              // 生成token规则
              let rule = {
    
    id:results[0].user_id,naems:results[0].user_name}
              // 生成token并响应:
              let token = createToken(rule)
              ctx.body = {
    
    cod: 200, msg: '登录成功!', userId: results[0].user_id, token: token}
            } else {
    
    
              ctx.body = {
    
    cod: 201, msg: '密码错误!'}
            }
          }  else {
    
    
            // 用户名不存在时:
            ctx.body ={
    
    cod: 202, msg: '用户不存在!'}
          }
          resolve()
        }
      } catch (err){
    
    
        reject()
        console.log('loginserve文件login登录接口错误:' + err)
      }
    })
  })
})

// 导出路由
module.exports = router

提示:数据库配置文件,生成token的文件我这里没有粘出

提示:本文图片等素材来源于网络,若有侵权,请发邮件至邮箱:[email protected]联系笔者 删除。

笔者:苦海

猜你喜欢

转载自blog.csdn.net/weixin_46758988/article/details/127586806
今日推荐