• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

凉梁凉糕

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

koa mongoose 实践篇,各种必要的功能总结;

https://www.cnblogs.com/xhliang/p/11913119.html 记录了一些理论知识,但是在实际开发过程中还存在很多疑惑,下面列举几个常用功能点;

1 倒叙,分页,总条数,模糊查询

router.get('/getList',async (ctx)=>{
  const List = mongoose.model('List')
  // 创建一个查询条件 利用$and 由于$and不能为空数组,所以初始化时设置了个空对象 
  const queryCriteria = {$and:[{}]}
  const { myId ,title, type, currentPage, pageSize} = ctx.query
  if(myId){
    queryCriteria.$and.push({myId:myId})
  }
  if(type){
    queryCriteria.$and.push({type:type})
  }
  if(title){
    // title 支持模糊查询
    const regTitle = new RegExp(title,'i')
    queryCriteria.$and.push({title:{$regex:regTitle}})
  }
  // 查询总条数
  const total = await List.countDocuments(queryCriteria)
  // 根据条件进行分页查询,limit控制返回的最大条数,skip控制第几页,sort用于排序(1正叙,-1倒叙)
  await List.find(queryCriteria).sort({time:-1}).limit(parseInt(pageSize)).skip((parseInt(currentPage)-1)*parseInt(pageSize)).then((res)=>{
    ctx.body = {
      code:200,
      data:{
        list:res,
        total:total
      }
    }
  })
})

 

2 关联查询,比如一个表中有aId bId id aId和bId都关联另外一个表,我想查询aId关联的表后再查询当前表之后返回内容;(没有找到更好的办法,如果有大神路过请指点)

实现法法:先根据条件进行关联查询,后再按条件查询都成功后返回给客户端数据;

 

3 字段必填的设定,新建利用required: true

const listSchema = new Schema({
  id:Schema.Types.ObjectId,
  name:{ type:String, required: true })

更新和删除数据时,非新建有的字段 如自动生成的id需要手动去验证,而新建时就required的字段,只需要设置运行验证器既可(详见第五点);(不知道有没有更好的办法,欢迎路过的给出较好的答案)

router.put('/updateList',async ctx=>{
  const List= mongoose.model('List')
  const updateId = ctx.request.body._id
  // 更新时id必选
  if(!updateId){
    ctx.body={
      code:405,
      message:"Id was not found"
    }
  }else{
    await List.update({_id:updateId},{$set:ctx.request.body}).then(res=>{
      ctx.body = {
        code:200,
        message:'Update success'
      }
    }).catch(err=>{
      console.log(err)
      ctx.body={
        code:500,
        message:err
      }
    })
  }
})

  

4 字段唯一性,不能被重复;

字段唯一性的控制是在new Schema时 设置字段的属性{unique:true}

const listSchema = new Schema({
  id:Schema.Types.ObjectId,
  name:{ type:String,unique:true },
  type:String,
  desc:String,
  aId:String,
  bId:String,
  time: { type: Date, default: Date.now() },
})

 

5 字段更新update时如何保证必填、唯一性和字段类型等也被验证

在官方文档中介绍了很多字段,其中runValidators:如果为真,则在此命令上运行更新验证器。更新验证器根据模型的模式验证更新操作,这样就保证了数据的准确性;

List.update({_id:updateId},{$set:ctx.request.body},{runValidators:true})

  还有一个字段 upsert (boolean) 如果文档不匹配,是否创建文档(false),一般更新的时候 不需要去创建文档 ,只要更新原来的内容既可可以设置为fasle,默认也是fasle

 

6 字段可能为Array类型, 也可以为String类型么?

可以利用mixed来实现:这样mykey就可以传入各种类型

const listSchema = new Schema({mykey:Schema.Types.Mixed})

  

7 对error的封装

针对数据库报出来的错误基本都是数据错误,想必填的未传递,唯一性的传递重复的值,类型与设定的不一致等等;

有两种方式,自己写方法去验证和封装数据库报出来的错误传递给客户端;

但是封装错误时发现mongodb的error没有太多规律,也没有专们的文档,一般返回的是res.message;封装数据库报出来的错误就会增加数据库的压力,若读写操作特别频繁的话建议自己封装方法;

 

8 使用jwt进行token鉴权 (需要先安装jwt 和中间件koa-jwt)

A- 服务端利用jwt生成token

//登录时,匹配成功后生成token并返回给客户端

const jwt = require('jsonwebtoken');
const keys = require('./../config/key.js')

const token = jwt.sign(payload,keys.secretkey,{expiresIn:3600})
ctx.body = {
    code: 200,
    message: '登录成功',
    data: {
        userName:result.userName,
        token:token
    }
};

B- web端,登录成功保存token,并在拦截器中统一添加token,

axios.interceptors.request.use(config => {
    const token = localStorage.getItem('token');
    config.headers.common['Authorization'] = 'Bearer ' + token;
    return config;
})

C- 服务端统一进行拦截对token进行验证,主要这个拦截器一定位于各个接口路由之前,否则不执行

const koaJwt = require('koa-jwt')
const keys = require('./config/key.js')

// token验证拦截器
app.use( function(ctx, next) {
  // console.log('执行了拦截器',ctx,next)
  return next().catch(err=>{
    console.log('tokenerr',err)
    if(err.status == 401){
      ctx.status = 401
      ctx.body = 'Protected resource, use Authorization header to get access\n'
    }else{
      throw err;
    }
  })
})
// 借用koa中间件对token进行验证 
// token 验证失败的时候会抛出401错误,因此需要添加错误处理,而且要放在 app.use(koajwt()) 之前,否则不执行。
app.use(koaJwt({ secret: keys.secretkey }).unless({
  path:['/user/loginUser','/user/logoutUser']
}))

但是注意,上面的方法并没有区分token的过期和无效,具体可以查看\node_modules\koa-jwt\lib\resolvers\auth-header.js 和 koa-jwt\lib\index.js,进行了统一处理;

 koajwt 封装了verify的方法,也可以自己写方法进行验证,下面伪代码提供一个思路;

let token = req.header.token
jwt.verify(token,keys.secretkey, (err,decoded)=>{
 if (err) {
      switch (err.name) {
        case 'JsonWebTokenError':
          res.status(403).send({ code: -1, msg: '无效的token' });
          break;
        case 'TokenExpiredError':
          res.status(403).send({ code: -1, msg: 'token过期' });
          break;
      }
    }   
}

  

jwt验证相关详细参考:https://github.com/lin-xin/blog/issues/28 

 

posted on 2020-06-30 11:36  凉梁凉糕  阅读(407)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3