zoukankan      html  css  js  c++  java
  • 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
    '
        }else{
          throw err;
        }
      })
    })
    // 借用koa中间件对token进行验证 
    // token 验证失败的时候会抛出401错误,因此需要添加错误处理,而且要放在 app.use(koajwt()) 之前,否则不执行。
    app.use(koaJwt({ secret: keys.secretkey }).unless({
      path:['/user/loginUser','/user/logoutUser']
    }))

    但是注意,上面的方法并没有区分token的过期和无效,具体可以查看 ode_moduleskoa-jwtlib esolversauth-header.js 和 koa-jwtlibindex.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 

  • 相关阅读:
    hadoop SecondNamenode 详解
    LaTeX的图片插入及排版[转]
    Secondary Namenode
    分布式文件系统元数据服务模型【转】
    Linux查看物理CPU个数、核数、逻辑CPU个数
    TCP的滑动窗口机制【转】
    sysctl.conf
    Iperf[转]
    CVE-2017-11882漏洞利用
    2017EIS CTFwriteup
  • 原文地址:https://www.cnblogs.com/xhliang/p/13212806.html
Copyright © 2011-2022 走看看