Jmeter学习和一个关于jmeter获取X-XSRF-TOKEN时的坑
现在想对一个接口做性能测试,需要测试它多个线程并发下的调用
1.新建测试计划和线程组
略
2.新建http接口
一个完整的http接口包含请求头和请求,这里就需要两个组件:HTTP request、HTTP Header Manager。
2-1 HTTP request
需要填写以下内容。
2-2 HTTP Header Manager
这里需要关注的是X-XSRF-TOKEN,它是动态的。
如果是第一次发请求,请求参数不带X-XSRF-TOKEN,响应头就会返回一个X-XSRF-TOKEN。
第二次请求就必须在请求头中带上上次请求返回的X-XSRF-TOKEN,否则就会返回403,并报错如下。
Invalid CSRF Token 'null' was found on the request parameter 'csrf' or header 'x-xsrf-token'
那么这里的难点就在于每次都需要从上一次请求的响应头中获取返回的X-XSRF-TOKEN,并设置到下一次请求的请求头中
响应头中要提取的数据长这样:
3.提取response Header返回的动态变量
这里介绍了正则表达式提取和边界表达式提取两种方法,任选一种即可。
遇到的一个坑,暂时不知道为什么:
在本地启动项目时,即项目地址的IP是localhost时,正则提取不到,必须用边界表达式提取;
在云服务器上启动时,即项目地址的IP是云服务器的IP时,边界表达式提取不到,必须用正则提取。
3-1 Regular Expression Extractor
通过正则表达式提取和引用X-XSRF-TOKEN
提取之后在下一个请求的请求头中这样引用
3-2 Boundary Extractor
通过边界表达式提取和引用X-XSRF-TOKEN
提取之后在下一个请求的请求头中这样引用
4.提取登录后response Data返回的token
要提取的token长这样
4-1 JSON Extractor
5.设置一个接口的多次调用
5-1 添加事务控制器-Transaction Controller
5-2 添加循环控制器-Loop Controller
放在事务控制器里面
5-3 添加计数器-Counter
放到循环控制器里面
5-4 添加BeanShell取样器-BeanShell Sampler
放到循环控制器里面
5-5 添加http接口
放到循环控制器里面
接口里面包含HTTP request和HTTP Header Manager,除此之外,要想对接口进行参数化,即多次调用接口每次传入不同的参数,还需要添加CSV数据文件配置
5-5-1 HTTP request
略
5-5-2 HTTP Header Manager
略
5-5-3 CSV Data Set Config
放到接口里面
6.添加结果树查看运行结果
放在线程组下面,就显示线程组的运行结果。
7.一个关于jmeter获取X-XSRF-TOKEN时的坑
一次业务需求中需要对某些业务接口进行接口性能测试。都是调试通过的接口,在jmeter中录入后调用却卡在鉴权的第一步,反复报403失败。
这里必须讲一下我们业务设计里调用接口的前提:X-XSRF-TOKEN和access_token双认证。
X-XSRF-TOKEN:在每一次请求时生成一个XSRF-TOKEN,必须在之后的每个请求中传递
access_token:在登陆成功后返回一个access_token,每一次业务接口调用都需要这个access_token
报错内容:
403 {"error":"access_denied","error_description":"Could not verify the provided CSRF token because your session was not found."}
也就是我还卡在第一步,登录接口都没调通,原因是没有携带X-XSRF-TOKEN发送请求。
尝试了n次之后,大概把失败的情况分为两种:
1.未添加HTTP Cookie Manager
2.添加了HTTP Cookie Manager
7-1 未添加HTTP Cookie Manager
(1)第一个请求:请求失败报403。没有携带X-XSRF-TOKEN时发送请求,响应中会自动返回一个X-XSRF-TOKEN,图略,下面有
(2)第二个请求:请求失败报403。请求头中携带从第一个请求响应头中提取到的X-XSRF-TOKEN
(3)第三个请求:请求失败报403。请求头中携带从第二个请求响应头中提取到的X-XSRF-TOKEN
所以得出结论:这里必须添加HTTP Cookie Manager。
如果不添加HTTP Cookie Manager,请求一个也成功不了,虽然我每次请求都带上了上一次请求返回的X-XSRF-TOKEN,请求仍然会失败报错。
7-2 添加了HTTP Cookie Manager
(1)第一个请求:请求失败报403。没有携带X-XSRF-TOKEN时发送请求,响应中会自动返回一个X-XSRF-TOKEN,如图所示
(2)第二个请求:请求成功报200。请求头中携带从第一个请求响应头中提取到的X-XSRF-TOKEN,但响应Header中本来应该有的【Set-Cookie: XSRF-TOKEN=…】却消失了
(3)第三个请求:请求失败报403。由于第二个请求返回的响应Header中没有XSRF-TOKEN,所以没有携带X-XSRF-TOKEN时发送请求,错误同第一个请求
7-3 原因分析
这个问题困扰了我非常非常久,并且也没有在网上搜索到同类问题,使用apifox、postman等工具都不会出现这种情况,只有jmeter反复失败:
-
尝试不添加HTTP Cookie Manager,一次请求也成功不了;
-
一旦添加HTTP Cookie Manager,第二次请求能够成功,但从第二次请求起,返回的响应头中的【Set-Cookie:XSRF-TOKEN=…】就没有了,导致后面请求全部失败,非常见鬼。
后来慢慢意识到原因可能是:【Set-Cookie:XSRF-TOKEN=…】第二次被返回过来时,它已经被交给HTTP Cookie Manager来管理了,就不在响应头中展示了。
延申发现,不仅仅是【XSRF-TOKEN】,所有响应头中的【Set-Cookie:xxx=】都只会在响应头中出现一次,第二次请求中返回【xxx】变量,jmeter就会将其交给HTTP Cookie Manager来管理,它也就不再显示在response header中了。
注:Set-Cookie开头的响应头内容,意味着把Set-Cookie中的键和值设置到cookie中
为了验证这个猜测,连续三次调用登录接口发现:
- 第一次调用:因为未携带X-XSRF-TOKEN,登录失败,返回的响应头中【Set-Cookie:XSRF-TOKEN=…】
- 第二次调用:携带X-XSRF-TOKEN,登录成功,返回的响应头中【Set-Cookie:XSRF-TOKEN=…】消失了,但多出【Set-Cookie:access_token=…】、【Set-Cookie:session_token=…】
- 第三次调用:登录失败,返回的响应头中没有任何【Set-Cookie:…】数据
出现过一次的【Set-Cookie:xxx=…】没有再出现第二次。
这个尝试不能完全证明我的猜测,但也没有证伪。
然后我开始进一步验证我所需要的结论:接口每次调用其实都返回了对应的【Set-Cookie:XSRF-TOKEN=…】,只是由于被jmeter的HTTP Cookie Manager管理了,所以第二次返回的XSRF-TOKEN不再存在于响应头中,而是存在于cookie中。
7-4 解决方案
那么只有第一次请求后需要用正则表达式获取响应头中的XSRF-TOKEN,第二次及之后就需要从cookie中去取它的值。
注:jmeter中从cookie中获取变量值语法:${COOKIE_变量名}
-
第一次请求:因为未携带X-XSRF-TOKEN,登录失败,返回的响应头中【Set-Cookie:XSRF-TOKEN=…】,图略
-
第二次请求:从边界表达式提取第一次请求返回的响应头中的XSRF-TOKEN
-
第三次请求:从cookie中提取第二次请求返回的响应头中的XSRF-TOKEN(被设置到cookie中,响应头中提取不到了)
-
第四次请求:从cookie中提取第三次请求返回的响应头中的XSRF-TOKEN(被设置到cookie中,响应头中提取不到了)
7-5 总结
所以整理之后的脚本进行合理的调整后应该长这样:
其中的每个部件:
(1)全局HTTP Cookie管理器
(2)全局HTTP请求头
(3)登录前置事务管理器、边界表达式提取器
-
登录前置事务管理器
-
边界表达式提取器
(4)登录事务管理器、登录请求头、json提取器
-
登录事务管理器
-
登录请求头
-
json提取器
(5)业务事务管理器、业务请求头
-
业务事务管理器
-
业务请求头
(6)结果树