美文网首页
杂谈-如何与恶势力做斗争-异常监控和测试

杂谈-如何与恶势力做斗争-异常监控和测试

作者: 酸萝卜 | 来源:发表于2018-03-19 16:23 被阅读0次

    上节, 前后端交互功能基本实现, 但在实际工程项目中这其实还不够。

    前端捕捉(怼)后端错误

    就拿项目中目前还存留的bug举例:

    在后端代码未启动的情况下,先运行前端服务,会返还如下错误

    这是因为后端未返回数据,导致的语法错误
    因此, 会产生三个问题

    1.程序无法运行
    2.页面不美观
    3.不利排查原因

    所以这里需要在不影响程序运行的前提下, 将错误以弹窗的形式展示出来,

    例如:


    此处输入图片的描述此处输入图片的描述

    这样不管是对开发人员,还是用户都更加友好

    具体做法:
    在ajax里做一层 状态码的判断

    const ajax = function(request) {
    
        var r = new XMLHttpRequest()
        r.open(request.method, request.url, true)
        if (request.contentType !== undefined) {
            r.setRequestHeader('Content-Type', request.contentType)
        }
        r.onreadystatechange = function(event) {
            if(r.readyState === 4) {
    +            if(r.status == 200) {
    +              const data = JSON.parse(r.response)
    +              request.success(data)
    +            }
    +            if(r.status == 500) {
    +              request.error()
    +            }
            }
        }
        if (request.method === 'GET') {
            r.send()
        } else {
            r.send(request.data)
        }
    }   
    
    
    //用Promise封装原生ajx
    const ajaxPromise = function(url, method, form) {
        var p = new Promise((resolve, reject) => {
            const request = {
                url: url,
                method: method,
                contentType: 'application/json',
                success: function(r) {
                    resolve(r)
                },
                error: function(e) {
                    const r = {
                        success: false,
                        message: '网络错误, 请重新尝试',
                    }
    +               resolve(r)
                },
            }
            if (method === 'post') {
                const data = JSON.stringify(form)
                request.data = data
            }
            ajax(request)
        })
        return p
    }
    

    然后在前端把message用弹窗显示出来

      //请求列表数据
      getDataSourseList = async () => {
    
        const { success, message, data } = await AllService.getList()
    +    if(success) {
          this.setState({
            dataSource:data,
          })
    +    }else {
    +      Message.error(`${message}`)
    +    }
      }
    

    Message为antd的弹窗组件, 如果只是简单显示可以用alret()

    这里分享一个插曲: antd组件的弹窗组件默认的组件名为小写 message
    而我这里协议定的字段message同样是小写, 所以变量冲突,
    这个时候我有两个选择

    • 要么我认怂,改协议
    • 要么,和恶势力怼到底
      我选择第二个,改了antd源码, 将小写换成了大写 :) 符合我们这次的主题

    当然情况还有很多, 到时根据状态码设置返回信息即可

    后端捕捉(怼)前端错误

    前端在调试过程中,有可能发送非法数据给后端,

    后端在不知情的情况下,操作数据库,很有可能会发生各种灵异事件

    所以后端需要对前端传递的参数进行校正, 并发出提醒

    这样才能更好的和前端合作(撕逼)

    具体做法:

    1. 引入校正函数
    //tools/commFunc.js
    
    
    /**
         * 校验 前端请求体
         * @param args 前端请求体
         * @param field_list 后端modal定义结构体的 keys
         * @param require_list 必须字段
         * @param is_not_strict 是否严格匹配
       */
    exports.assemble_args = function (args, field_list, require_list, is_not_strict) {
      let kwargs = {};
      let key_list = [];
      let err_msg = false;
    
      for (let field_name of field_list) {
        let has_key = (args[field_name] !== undefined);
        if (!is_not_strict) {
          has_key = has_key && (args[field_name] !== '');
        }
        if (has_key) {
          let key = field_name;
          let value = args[field_name];
          if (typeof value === 'string') {
            value = value.trim();
          } else if (field_name == 'id') {
            value = parseInt(value);
          }
          key_list.push(field_name);
          kwargs[key] = value;
        }
      }
    
      if (require_list && require_list.length) {
        let lack_params = [];
        for (let k of require_list) {
          if (key_list.indexOf(k) == -1) {
            lack_params.push(k);
          }
        }
    
        if (lack_params.length) {
          err_msg = `lack params:${lack_params.toString()}`
          //throw err_msg;
        }
      }
    
      return { kwargs, err_msg };
    };
    
    exports.goto_err = function (ret, err_msg) {
      ret.success = false;
      ret.message = err_msg;
      ret.code = 400;
      return ret;
    };
    

    2.检查请求体中是否有必须字段, 若缺失, 则把缺失信息发送给前端

    //routes/all/js
    
    main.post('/update', async (request, response) => {
    
      let ret = {
      "success": true,
      "code": 200,
      "message": "",
      "data": [],
      }
    
      const body = request.body,
              id = body.id || 0,
              status = body.status || 0
    - const args = body
      if (!id) {
        //新建
    
    +    //后端定义的keys
    +    const field_list = Object.keys(Model.schema.paths).filter(e=> e!='_id' && e!='id')
    +    //检查请求体中是否有 name, age, address
    +    //若缺失,则把缺失信息发送给前端
    +    const { kwargs, err_msg } = commFunc.assemble_args(body, field_list, ['name', 'age', 'address'])
    
    +    if( err_msg ) {
    +      let err = commFunc.goto_err(ret, err_msg)
    +      response.send(err)
    +      return
    +    }
    
        const dataSourceObj = await Model.create(kwargs)
    
        ret.data = {
          id: dataSourceObj.id, create:true
        }
    
      } else if (!status) {
        //修改
     +   const kwargs = body
    
        const dataSourceObj = await Model.findOne({id: kwargs.id})
    
    +    if(!dataSourceObj) {
    +      let err = commFunc.goto_err(ret, `dataSourceInfo id:${kwargs.id} query empty`)
    +      response.send(err)
    +      return
    +    }
    
        for ( let key in kwargs) {
          if(key =='_id' || key =='id' ) {
            continue
          }
          dataSourceObj[key]= kwargs[key]
        }
    
        const new_dataSourceObj = await dataSourceObj.save()
    
        ret.data = {
          id: new_dataSourceObj.id, update:true
        }
    
      } else if (status === -1){
        //删除
    +    const kwargs = body
    
        const dataSourceObj = await Model.findOne({id: kwargs.id})
    
    +    if(!dataSourceObj) {
    +      let err = commFunc.goto_err(ret, `dataSourceInfo id:${kwargs.id} query empty`)
    +      response.send(err)
    +      return
    +    }
    
        const remove = await dataSourceObj.remove()
    
        ret.data = {
          id: dataSourceObj.id, delete:true
        }
    
      }
    
      response.send(ret)
    })
    
    

    测试失败示例:

    • 创建时缺少参数


      此处输入图片的描述此处输入图片的描述
    • 修改, 删除时,id不存在


      此处输入图片的描述此处输入图片的描述

    (完...)

    相关文章

      网友评论

          本文标题:杂谈-如何与恶势力做斗争-异常监控和测试

          本文链接:https://www.haomeiwen.com/subject/gwepqftx.html