LoadRunner脚本开发:接口关联和md5加密(四)
一. 关联一:登录接口依赖注册接口请求参数中的mobile
web_reg_save_param_regexp的使用
{randomPhone}的属性设置
源码:先请求注册接口,注册接口请求成功后,再去请求登录接口,登录和注册的手机号一致
Action() { //定义固定参数 lr_save_string("192.168.0.105", "host"); lr_save_string("8080", "port"); lr_save_string("/mobile/api", "func"); //提取token值 web_reg_save_param_regexp( "ParamName=register_token", "RegExp=token\":\"(.*?)\"", "Ordinal=1", SEARCH_FILTERS, LAST);
//注册接口 web_custom_request("register", "URL=http://{host}:{port}{func}/user/register", "Method=POST", "TargetFrame=", "Resource=0", "Referer=", "EncType=application/json;charset=utf-8", "Body={\"mobile\":\"138{randomPhone}\",\"password\":\"123456\",\"code\":\"3367\",\"platform\":\"windows\",\"username\":\"test11\",\"sex\":1,\"age\":20,\"email\":\"123456@qq.com\"}", LAST); //lr_eval_string()函数是获取值 //如果注册成功,继续登录 if(lr_eval_string("{register_token}")) { lr_output_message("===========注册成功============="); web_custom_request("login", "URL=http://{host}:{port}{func}/user/login", "Method=POST", "TargetFrame=", "Resource=0", "Referer=", "EncType=application/json;charset=utf-8", "Body={\"mobile\":\"138{randomPhone}\", \"gqid\":\"\", \"password\":\"123456\"}", LAST); } else { lr_output_message("===========注册失败============="); } return 0; }
二. 关联二:充值密码接口需要登录接口的返回值token作为入参
web_reg_save_param_regexp的使用
lr_eval_string()的理解
先看个例子:如果参数 register_gqid未定义,那么gqid的值应该默认为"{register_gqid}"
Action()
{
lr_eval_string("{register_gqid}");
lr_save_string(lr_eval_string("{register_gqid}"), "gqid");
lr_output_message(lr_eval_string("{gqid}"));
return 0;
}
那么,我们之前用这种形式判断到底对不对:if(lr_eval_string("{register_gqid}"))——这个值会不会永远是True
因为register_gqid参数是从注册接口的响应结果里匹配的,如果匹配不到,会不会采用默认值"{register_gqid}"。答案是否定的,因为register_gqid有定义,它的定义就是去响应结果里进行正则匹配,无外乎两种结果,1. 能拿到,正常进行下面的if判断,2. 拿不到,进行if判断之前就报错了,不存在默认值。这里需要区分lr_eval_string()参数有没有定义的情况
源码
Action() { //定义固定参数 lr_save_string("192.168.0.105", "host"); lr_save_string("8080", "port"); lr_save_string("/mobile/api", "func"); //统计gqid出现的次数 // web_reg_find("Text=gqid", // "SaveCount=gqid_count", // LAST); //提取gqid值 web_reg_save_param_regexp( "ParamName=register_gqid", "RegExp=gqid\":\"(.*?)\"", "Ordinal=1", SEARCH_FILTERS, LAST); //提取登录后的token值 web_reg_save_param_regexp( "ParamName=login_token", "RegExp=token\":\"(.*?)\"", "Ordinal=1", SEARCH_FILTERS, LAST); //注册接口 web_custom_request("register", "URL=http://{host}:{port}{func}/user/register", "Method=POST", "TargetFrame=", "Resource=0", "Referer=", "EncType=application/json;charset=utf-8", "Body={\"mobile\":\"138{randomPhone}\",\"password\":\"123456\",\"code\":\"3367\",\"platform\":\"windows\",\"username\":\"test11\",\"sex\":1,\"age\":20,\"email\":\"123456@qq.com\"}", LAST); //lr_eval_string()函数是获取参数值,如果参数值不存在,则对应的字符串"{register_gqid}", //因此 if(lr_eval_string("{register_gqid}"))始终为true //方法一:atoi()转换 //if(atoi(lr_eval_string("{register_gqid}"))) //方法二:SaveCount //if (atoi(lr_eval_string("{gqid_count}")) == 1) //如果提前定义了变量,匹配只有两种情况,1. 能匹配到,进入if判断,2. 不能匹配到,if判断前就直接抛错了,因此不存在默认值的情况。只有没有提前定义变量,才会存在默认值 //if(atoi(lr_eval_string("{register_gqid}"))) { if(lr_eval_string("{register_gqid}")) { lr_output_message("===========注册成功============="); //如果注册成功,继续登录 web_custom_request("login", "URL=http://{host}:{port}{func}/user/login", "Method=POST", "TargetFrame=", "Resource=0", "Referer=", "EncType=application/json;charset=utf-8", "Body={\"mobile\":\"\", \"gqid\":\"{register_gqid}\", \"password\":\"123456\"}", LAST); } else { lr_output_message("===========注册失败============="); return -1; } if(lr_eval_string("{login_token}")) { lr_output_message("===========登录成功================"); lr_save_string(Change_to_Md5("123456_loadrunner"), "payPwd"); //如果登录成功,则重置支付密码 web_custom_request("recharge", "URL=http://{host}:{port}{func}/user/resetpaypwd", "Method=POST", "TargetFrame=", "Resource=0", "Referer=", "EncType=application/json;charset=utf-8", "Body={\"token\":\"{login_token}\", \"password\":\"{payPwd}\"}", LAST); } else { lr_output_message("===========登录失败================"); return -1; } return 0; }
三. md5加密:重置支付密码需要的支付密码为md5加密
引入md5.h
选中Extra Files,点击右键,出现Create New File...和Add Files to Script...
两种方式均可以,但建议选择第一种,因为第二种有可能出现乱码,第一种的做法是,新建一个md5.h文件,将md5.h中的代码拷贝进去
然后在globals.h中添加一个引入 #include "md5.h"
真正的Action中是这样调用的:代码同上
运行结果
Virtual User Script started at : 2019/11/9 22:00:25 Starting action vuser_init. Web Turbo Replay of LoadRunner 12.0.0 for Windows 2008 R2; build 2739 (Nov 30 2014 23:13:05) [MsgId: MMSG-27143] Run mode: HTML [MsgId: MMSG-26993] Run-Time Settings file: "C:\Users\beck\Documents\VuGen\Scripts\WebHttpHtml10\\default.cfg" [MsgId: MMSG-27141] Ending action vuser_init. Running Vuser... Starting iteration 1. Maximum number of concurrent connections per server: 6 [MsgId: MMSG-26989] Starting action Action. Action.c(6): Notify: Saving Parameter "host = 192.168.0.105". Action.c(7): Notify: Saving Parameter "port = 8080". Action.c(8): Notify: Saving Parameter "func = /mobile/api". Action.c(19): web_reg_save_param_regexp started [MsgId: MMSG-26355] Action.c(19): Registering web_reg_save_param_regexp was successful [MsgId: MMSG-26390] Action.c(29): web_reg_save_param_regexp started [MsgId: MMSG-26355] Action.c(29): Registering web_reg_save_param_regexp was successful [MsgId: MMSG-26390] Action.c(39): web_custom_request("register") started [MsgId: MMSG-26355] Action.c(39): Notify: Parameter Substitution: parameter "host" = "192.168.0.105" Action.c(39): Notify: Parameter Substitution: parameter "port" = "8080" Action.c(39): Notify: Parameter Substitution: parameter "func" = "/mobile/api" Action.c(39): Notify: Parameter Substitution: parameter "randomPhone" = "93990327" Action.c(39): t=1106ms: 157-byte response headers for "http://192.168.0.105:8080/mobile/api/user/register" (RelFrameId=1, Internal ID=1) Action.c(39): HTTP/1.1 200 OK\r\n Action.c(39): Server: Apache-Coyote/1.1\r\n Action.c(39): Content-Type: application/json;charset=UTF-8\r\n Action.c(39): Transfer-Encoding: chunked\r\n Action.c(39): Date: Mon, 28 Oct 2019 23:26:50 GMT\r\n Action.c(39): \r\n Action.c(39): t=1113ms: 5-byte chunked response overhead for "http://192.168.0.105:8080/mobile/api/user/register" (RelFrameId=1, Internal ID=1) Action.c(39): 166\r\n Action.c(39): t=1113ms: 7-byte chunked response overhead for "http://192.168.0.105:8080/mobile/api/user/register" (RelFrameId=1, Internal ID=1) Action.c(39): \r\n Action.c(39): 0\r\n Action.c(39): \r\n Action.c(39): t=1114ms: 358-byte chunked response body for "http://192.168.0.105:8080/mobile/api/user/register" (RelFrameId=1, Internal ID=1) Action.c(39): {"code":0,"msg":"鎴愬姛璋冪敤","data":{"id":242,"username":"test11","sex":1,"age":20,"mobi Action.c(39): le":"13893990327","email":"123456@qq.com","gqid":"4000052","money":0.0,"pmoney":100.0,"cre Action.c(39): atetime":1572305210479,"lasttime":1572305210479,"token":"nHEkcINdHWwVJ88O4zzNmMuvozuA4oRex Action.c(39): FHxx4VE6jNF8VRdp74NLQDaEW4JaHWMxRU/jxaEwo/fQbjJJq9BrA==","identity":"7a319e915d5a0661"}} Action.c(39): HTML parsing not performed for Content-Type "application/json" ("ParseHtmlContentType" Run-Time Setting is "TEXT"). URL="http://192.168.0.105:8080/mobile/api/user/register" [MsgId: MMSG-26548] Action.c(39): Notify: Saving Parameter "register_gqid = 4000052". Action.c(39): Notify: Saving Parameter "login_token = nHEkcINdHWwVJ88O4zzNmMuvozuA4oRexFHxx4VE6jNF8VRdp74NLQDaEW4JaHWMxRU/jxaEwo/fQbjJJq9BrA==". Action.c(39): web_custom_request("register") was successful, 358 body bytes, 157 header bytes, 12 chunking overhead bytes [MsgId: MMSG-26385] Action.c(60): Notify: Parameter Substitution: parameter "register_gqid" = "4000052" Action.c(62): ===========注册成功============= Action.c(65): web_custom_request("login") started [MsgId: MMSG-26355] Action.c(65): Notify: Parameter Substitution: parameter "host" = "192.168.0.105" Action.c(65): Notify: Parameter Substitution: parameter "port" = "8080" Action.c(65): Notify: Parameter Substitution: parameter "func" = "/mobile/api" Action.c(65): Notify: Parameter Substitution: parameter "register_gqid" = "4000052" Action.c(65): t=1187ms: 157-byte response headers for "http://192.168.0.105:8080/mobile/api/user/login" (RelFrameId=1, Internal ID=2) Action.c(65): HTTP/1.1 200 OK\r\n Action.c(65): Server: Apache-Coyote/1.1\r\n Action.c(65): Content-Type: application/json;charset=UTF-8\r\n Action.c(65): Transfer-Encoding: chunked\r\n Action.c(65): Date: Mon, 28 Oct 2019 23:26:50 GMT\r\n Action.c(65): \r\n Action.c(65): t=1188ms: 5-byte chunked response overhead for "http://192.168.0.105:8080/mobile/api/user/login" (RelFrameId=1, Internal ID=2) Action.c(65): 14e\r\n Action.c(65): t=1188ms: 7-byte chunked response overhead for "http://192.168.0.105:8080/mobile/api/user/login" (RelFrameId=1, Internal ID=2) Action.c(65): \r\n Action.c(65): 0\r\n Action.c(65): \r\n Action.c(65): t=1189ms: 334-byte chunked response body for "http://192.168.0.105:8080/mobile/api/user/login" (RelFrameId=1, Internal ID=2) Action.c(65): {"code":0,"msg":"鎴愬姛璋冪敤","data":{"id":80,"username":"4000003","sex":1,"age":20,"mobi Action.c(65): le":"","email":"","gqid":"4000003","money":0.0,"pmoney":100.0,"createtime":1448515307000," Action.c(65): lasttime":1572305210559,"token":"Gv0e9i65zoArjkWP5i5z8NT2JruL2vYAcHEIhHtI4yzJCkgj2tTxrjgz3 Action.c(65): eEAEEyxxRU/jxaEwo/fQbjJJq9BrA==","identity":"82afaa6d5bd13b20"}} Action.c(65): HTML parsing not performed for Content-Type "application/json" ("ParseHtmlContentType" Run-Time Setting is "TEXT"). URL="http://192.168.0.105:8080/mobile/api/user/login" [MsgId: MMSG-26548] Action.c(65): web_custom_request("login") was successful, 334 body bytes, 157 header bytes, 12 chunking overhead bytes [MsgId: MMSG-26385] Action.c(81): Notify: Parameter Substitution: parameter "login_token" = "nHEkcINdHWwVJ88O4zzNmMuvozuA4oRexFHxx4VE6jNF8VRdp74NLQDaEW4JaHWMxRU/jxaEwo/fQbjJJq9BrA==" Action.c(83): ===========登录成功================ Action.c(84): Notify: Saving Parameter "payPwd = cfff73adc49ec25d1ee1b3ec5e8ea5ef". Action.c(87): web_custom_request("recharge") started [MsgId: MMSG-26355] Action.c(87): Notify: Parameter Substitution: parameter "host" = "192.168.0.105" Action.c(87): Notify: Parameter Substitution: parameter "port" = "8080" Action.c(87): Notify: Parameter Substitution: parameter "func" = "/mobile/api" Action.c(87): Notify: Parameter Substitution: parameter "login_token" = "nHEkcINdHWwVJ88O4zzNmMuvozuA4oRexFHxx4VE6jNF8VRdp74NLQDaEW4JaHWMxRU/jxaEwo/fQbjJJq9BrA==" Action.c(87): Notify: Parameter Substitution: parameter "payPwd" = "cfff73adc49ec25d1ee1b3ec5e8ea5ef" Action.c(87): t=1221ms: 157-byte response headers for "http://192.168.0.105:8080/mobile/api/user/resetpaypwd" (RelFrameId=1, Internal ID=3) Action.c(87): HTTP/1.1 200 OK\r\n Action.c(87): Server: Apache-Coyote/1.1\r\n Action.c(87): Content-Type: application/json;charset=UTF-8\r\n Action.c(87): Transfer-Encoding: chunked\r\n Action.c(87): Date: Mon, 28 Oct 2019 23:26:50 GMT\r\n Action.c(87): \r\n Action.c(87): t=1222ms: 4-byte chunked response overhead for "http://192.168.0.105:8080/mobile/api/user/resetpaypwd" (RelFrameId=1, Internal ID=3) Action.c(87): 29\r\n Action.c(87): t=1222ms: 7-byte chunked response overhead for "http://192.168.0.105:8080/mobile/api/user/resetpaypwd" (RelFrameId=1, Internal ID=3) Action.c(87): \r\n Action.c(87): 0\r\n Action.c(87): \r\n Action.c(87): t=1223ms: 41-byte chunked response body for "http://192.168.0.105:8080/mobile/api/user/resetpaypwd" (RelFrameId=1, Internal ID=3) Action.c(87): {"code":0,"msg":"鎴愬姛璋冪敤","data":{}} Action.c(87): HTML parsing not performed for Content-Type "application/json" ("ParseHtmlContentType" Run-Time Setting is "TEXT"). URL="http://192.168.0.105:8080/mobile/api/user/resetpaypwd" [MsgId: MMSG-26548] Action.c(87): web_custom_request("recharge") was successful, 41 body bytes, 157 header bytes, 11 chunking overhead bytes [MsgId: MMSG-26385] Ending action Action. Ending iteration 1. Ending Vuser... Starting action vuser_end. Ending action vuser_end. Vuser Terminated.
数据库检查
可以看到 pay_pwd 字段已被更新