js校验原生客户端日志开发

video_js_template

工程编译与使用

工程编译

  • 使用./wbinit.sh脚本,安装本工程需要的相关依赖;
  • 使用npm run webpack,调用./wbnpx.sh脚本进行webpack打包;使用node ./dist/bundle.js可执行打包后的bundle.js文件;
  • 使用npm run build,内部调用./wbnpx.sh;./wbversion.sh build脚本进行webpack打包,同时打出来的bundle.js会生成version版本变量,可使用npm run build 2来指定build号为2,不传build号则版本信息里的build号会自增;版本信息存储在version.data文件中;
  • 使用npm run release,调用./wbnpx.sh;./wbversion.sh release脚本进行webpack打包,同时打出来的bundle.js会生成version版本变量,可利用npm run release 1.0命令指定版本号,如果不传版本号会展示最后一次的version号;如果本地安装了wbcompile工具,在使用npm run release xx时会直接上传bundle.js到ftp对应目录下;
  • 使用npm run start可启动nodemon服务,此服务会监听工程目录下的/tscompile文件夹文件的改动,若有更改时自动运行项目;
  • 使用npm run tscompile触发编译或者Command + shift + b手动触发tasks.json任务,可编译/src/下的所有ts文件,把编译后的中间产物输出到/tscompile文件夹下,如果开启了nodemon服务,会自动触发nodemon的watch事件,触发热更新;配置了launch.json文件,可使用VSCode自带的运行和调试(command + shift + D)对项目中的具体代码进行断点和调试开发;
  • 使用npm run dev,打开本地server,方便利用chrome调试;
  • 终端 -> 运行任务 -> 显示所有任务 -> tsc:监视 - tsconfig.json,可以动态编译ts;

设计思路

整体流程

原生端上执行bundle.js代码,获取js运行环境,然后通过调用js函数并把当前日志json和这条日志对应的js模板代码作为参数,来对日志进行校验,js会返回校验的结果,端上根据返回结果做UI显示;

初步解决方案

js校验api介绍

校验工具暴露出的接口如下

  • loadTemplate(code: string): 加载模板字符串,参数为模板字符串,可以为json或者js模板字符串,内部会自动判断;
  • loadJSTemplate(code: string): 参数为动态下发的js文件的模板字符串;可把需要的js模板文件加载执行;
  • loadJsonTemplate(jsonString: string): 参数为下发的json格式的模板字符串;加载json模板;
  • checkFunction(log: string, context: string): 第一个参数为需要校验的json字符串,第二个参数为需要增量结合模板校验的context;
  • loadJSTemplateAndExecute(code: string, log: string, context: string): 加载单个js模板,并立即执行校验;
  • loadJsonTemplateAndExecute(jsonString: string, log: string, context: string): 加载单个json模板,并立即执行校验;

loadTemplate、loadJSTemplate、loadJsonTemplate 这三个方法的返回值是json数组,示例如下:

[{"id":"799","items":[{"name":"uicode","logic":3,"rule":"^[0-9]+$"},{"name":"fid","rule":"@fid == 232673"},{"name":"friend","logic":1,"rule":"hi amigo #$$#, my name is #$placeholder$#, my age is #$p$#,see you!"},{"name":"source_info","rule":"(@mid >= 0) && (@source_info include 'face_sign_1')"},{"name":"mid","logic":4},{"name":"ext","sub":[{"name":"objectid","logic":3,"rule":"^[0-9]{1,}(:|.{3})[0-9]+$"},{"name":"authorid","logic":3,"rule":"[0-9]{1,}$"}]}]},{"id":"template123","items":[{"name":"fid","rule":"@fid == 232673"}]},{"items":[{"name":"fid","rule":"@fid == 232673"}],"id":"template456"}]

checkFunction、loadJSTemplateAndExecute、loadJsonTemplateAndExecute 三个方法的返回值为json,示例如下:


{"success":true,"code":1,"reason":"","results":[{"key":"uicode","value":"10001344","success":true,"logic":3,"required":false,"rule":"^[0-9]+$"},{"key":"fid","value":"232673","success":true,"logic":"","required":false,"rule":"@fid == 232673"},{"key":"friend","value":"zjd","success":true,"logic":1,"required":false,"rule":"hi amigo zjd, my name is wyb, my age is 18,see you!"},{"key":"source_info","value":"face_sign_1","success":true,"logic":"","required":false,"rule":"(@mid >= 0) && (@source_info include 'face_sign_1')"},{"key":"mid","value":"4805675316939808","success":true,"logic":4,"required":false,"rule":"Function: e=>!!e.mid&&/^[0-9]+$/.test(e.mid)"},{"key":"objectid","value":"1034%3A4805674547478607","success":true,"logic":3,"required":false,"rule":"^[0-9]{1,}(:|.{3})[0-9]+$"},{"key":"authorid","value":"7168897192","success":true,"logic":3,"required":false,"rule":"[0-9]{1,}$"}]}

工具脚本的使用

使用下面命令安装配套的脚本工具:


# 一键安装wbcompile.sh脚本
sudo curl http://ftp.client.weibo.cn/UI_Image/Video/ShellTools/installwbcompile.sh | sh

wbcompile脚本具有处理新建日志模板、编译commonJS文件、上传ftp等功能,具体可通过wbcompile -h查看帮助命令;常用方法总结如下:

  • wbcompile -t templateName可在当前执行脚本的目录下生成templateName.ts模板文件,可根据需求修改模板文件保存;
  • wbcompile -i inputFile(inputDir) -o outputDir 或者 wbcompile inputFile(inputDir) outputDir命令对需要编译的文件进行编译,支持对typescriptES6文件进行统一编译成ES5规范; -i 是需要编译的文件或文件夹,如果 -i 参数为文件夹,支持递归遍历子目录编译;-o 是编译后输出的文件路径;
  • wbcompile -u file调用上传命令,上传编译好的ES5文件到ftp服务器;

日志模板的定义

property 含义 备注
name 需要校验的字段名,如uicode;
required 是否是必须字段,即如果校验失败是否抛异常;默认是false;
sub 如果验证的字段是复合型,比如ext字段,则支持多级嵌套;
logic 逻辑关系,值含义枚举:0:表达式解析;1:包含;2:相等;3:正则;4:js函数;
rule 和logic绑定关系,需要用来校验的rule; logic为4时,rule为函数或者函数字符串,会调用rule函数来判断校验结果,参数为整个json转成的对象;logic为0或者不传时,默认使用表达式解析规则;可支持常用一元、二元操作符以及逻辑关系;

rule支持placeholder功能,可使用#$ here-could-be-anystring $#包括起来的占位符来进行占位,在context传进来时替换占位符,如代码所示:

// 如context 有个friend字段,需要动态拼接rule规则,可按下面示例所示构建rule,可用逗号分割多个值替换多个占位符
var context = '{"friend":"zjd,wyb,18"}';

{
    name:"friend",
    rule:"hi amigo #$$#, my name is #$placeholder$#, my age is #$p$#,see you!"
}

// 最终拼接好的用来校验的rule
hi amigo zjd, my name is wyb, my age is 18,see you!

遇到的问题和解决办法

  • 原生JSContext不支持执行多个 es6 js文件,需要合并 es6 js 文件;
  • 使用webpack解决多个js文件合并问题,但是使用webpackbundle.js文件是直接执行的匿名函数,一些export的方法名原生执行不到;
  • 编写wbnpx.sh脚本,对webpack生成的bundle.js文件做处理。匹配入口文件app.js中需要导出的对象,在bundle.js里直接写入;
  • 项目中js语法太过灵活,无法做类型定义,项目整体切换到typescript
  • 单个js文件中可包含多个校验模板,模板和校验log逻辑拆分;
  • 利用eval()函数动态执行js文件字符串或者json模板字符串,可动态下发js代码执行;
  • 校验逻辑新增规则,可在js模板里定义一个function对象或者function字符串来进行校验,利用eval函数动态校验规则;同理json模板里也可返回function字符串;function的参数为json转成的对象
  • 编写wbcompile.sh脚本,脚本可以生成模板文件,执行ts文件es6文件转为es5文件,支持递归遍历子目录编译;支持直接上传ftp服务器;
  • 增加表达式解析规则,支持常用逻辑表达式解析,根据LL(1)递归下降词法算法编写解析器,读取输入表达式生成AST语法树,操作语法树节点运算校验;表达式支持一元、二元操作符,支持逻辑关系,支持变量的使用,示例如:(@mid === (1+2+3)*2-5) && (@source_info include 'face_sign_1')
  • 编写版本管理脚本,记录每次build行为,保存为version.data便于读取;支持build号自增,支持指定release version
  • 在使用wbcompile -u上传本地创建好的模板文件时,先通过ftp拉取已经存在的模板配置configurationtable.json文件;通过脚本创建中间处理文件temp_merge_table.js,把模板js文件的内容直接输入到temp_merge_table.js文件中,把configurationtable.json配置文件的json字符串通过脚本转为temp_merge_table.js中的一个变量,然后通过编写代码做配置文件的合并;合并完成以后生成新的configurationtable.json文件,上传到ftp对应目录下;
  • done.