Jmeter MD5插件
实际业务中,会要求 HTTP 协议中附加 MD5 校验字段, 防止请求参数被恶意篡改, 对于开发同学来说, 这是个很简单的需求。 但是给自动化测试增加了难度, Jmeter 原生不支持这个功能,应测试同学要求,开发了一个简单的小插件。
一、功能分析
1. MD5 值生成规则:
Step1, HTTP 请求增加新参数 ct, 值为当前时间毫秒数;
Step2, 获取HTTP 请求所有参数,放入 list;
Step3, List 增加新参数 key, 值根据通信协议的双方约定(不在 http请求中传递 );
Step4, 把 List 按参数名进行排序,把排序后的参数值进行拼接, 对拼接结果执行 MD5 运算;
Step5, Http请求增加新参数 code, 值是 Step4 计算得出的值。
注:不同业务此规则可能略有差异,请根据实际情况实现。
2. MD5 值需要在 HTTP 请求之前添加 (属于 Jmeter 前置处理器范围)。
二、需要解决的问题
1. 在 Jmeter 的 HTTP 请求中获取参数、 增加参数
2. 实现 MD5 的具体逻辑
3. 在合适的时机把生成的 MD5 校验值附加到 HTTP 请求参数中
4. 集成到 Jmeter 菜单中,方便使用。
三、解决步骤
1. 因之前没有 Jmeter 插件开发经验, 需要先学习一下如何开发。 网上搜集了一下资料没有太明确的方案;不过Jmeter本身有很多插件,就从这里入手,分析一下现有插件的实现方式,然后用相同的方式来完成插件。
2. 到 Apache 官网 下载 Jmeter 的源代码(我使用的2.11版), 根据 Jmeter 界面中看到的关键字来定位插件代码位置。
3. 开发的是 Http Sampler 插件,那么,我们先搜索一下Http Sampler关键字, 可以找到 HttpSampler.java;阅读代码可以得到问题1的答案。
4. 问题2不在赘述。
5. 分析问题3, 我们需要在 HTTP 请求发送前, 进行插件调用, 可以得知这个插件应该是属于前置处理器范围的。 通过分析前置处理器的代码应该可以解决这个问题。Jmeter 插件中第一个前置处理器是 BeanShell PreProcessor, 用 BeanShell 和 PreProcessor 关键字查找源代码, 查到了类 BeanShellPreProcessor.java;阅读这个类及父类代码可以得到问题3、问题4的答案。
四、具体代码
1. MD5PreProcessor.java
 public class MD5PreProcessor  extends AbstractTestElement implements TestStateListener, PreProcessor, Serializable {
     private static final long serialVersionUID = -1L;
     private static final Logger LOGGER = LoggingManager.getLoggerForClass();
     /**
      * Default constructor.
      */
     public MD5PreProcessor() {
     }
     @Override
     public void testStarted() {
     }
     @Override
     public void testStarted(String host) {
     }
     @Override
     public void testEnded() {
     }
     @Override
     public void testEnded(String host) {
     }
     /*
      * ------------------------------------------------------------------------
      * Methods implemented from interface org.apache.jmeter.config.Modifier
      * ------------------------------------------------------------------------
      */
     @Override
     public void process() {
         Sampler sam = getThreadContext().getCurrentSampler();
         HTTPSamplerBase sampler = null;
         if (!(sam instanceof HTTPSamplerBase)) {
             return;
         } else {
             sampler = (HTTPSamplerBase) sam;
         }
         // 排序参数和header(appversion, os)
         java.util.List<KeyValue> list = new ArrayList<KeyValue>();
         sampler.addArgument("ct", System.currentTimeMillis() + "");
         // 添加参数列表
         Arguments arguments = sampler.getArguments();
         PropertyIterator iter = arguments.iterator();
         while(iter.hasNext()) {
             Argument arg = getFromJMeterProperty(iter.next());
             KeyValue kv = new KeyValue(arg.getName(), arg.getValue());
             list.add(kv);
         }
         // 添加header: os appVersion
         HeaderManager headerManager = sampler.getHeaderManager();
         for(int i = 0; i < headerManager.getHeaders().size(); i++) {
             Header a = headerManager.getHeader(i);
             if("os".equals(a.getName()) || "appVersion".equals(a.getName())) {
                 list.add(new KeyValue(a.getName(), a.getValue()));
             }
         }
         // 加盐
         list.add(new KeyValue("key", "+MrK}6seb#$E"));
         StringBuffer sbu = new StringBuffer();
         // 按顺序拼接所有参数值
         Collections.sort(list);
         for(KeyValue kv : list) {
             //LOGGER.info("key: "+kv.getKey()+", value:"+kv.getValue());
             sbu.append(kv.getValue());
         }
         try {
             MessageDigest md = MessageDigest.getInstance("MD5");
             byte[] md5sum = md.digest(URLEncoder.encode(sbu.toString(), "UTF-8").getBytes());
             String md5Code = new BigInteger(1, md5sum).toString(16);
             while(md5Code.length() < 32 ){
                 md5Code = "0"+md5Code;
             }
             LOGGER.info("before: "+sbu.toString()+",encode:"+URLEncoder.encode(sbu.toString(), "UTF-8")+",end:"+md5Code);
             sampler.addArgument("code", md5Code);
         } catch(Exception e) {
             e.printStackTrace();
         }
     }
     private Argument getFromJMeterProperty(JMeterProperty o) {
         return (Argument)o.getObjectValue();
     }
     /*
      * ------------------------------------------------------------------------
      * Methods
      * ------------------------------------------------------------------------
      */
     private class KeyValue implements Comparable<KeyValue> {
         private String key;
         private String value;
         public KeyValue(String key, String value) {
             this.key = key;
             this.value = value;
         }
         @Override
         public int compareTo(KeyValue o) {
             int  result = this.key.compareTo(o.key);
             if(result == 0) {
                 result = this.value.compareTo(o.value);
             }
             return result;
         }
         public String getKey() {
             return key;
         }
         public String getValue() {
             return value;
         }
     }
 }
2. Md5PreProcessorGui.java
public class Md5PreProcessorGui extends AbstractPreProcessorGui {
    private static final long serialVersionUID = 100L;
    private static final Logger LOGGER = LoggingManager.getLoggerForClass();
    public Md5PreProcessorGui() {
        createGui();
    }
    public String getStaticLabel() {
        return "MD5 Encode";
    }
    public String getLabelResource() {
        return getClass().getCanonicalName();
    }
    public void configure(TestElement element) {
        super.configure(element);
    }
    public TestElement createTestElement() {
        MD5PreProcessor sampler = new MD5PreProcessor();
        modifyTestElement(sampler);
        return sampler;
    }
    public void modifyTestElement(TestElement element) {
        element.clear();
        configureTestElement(element);
    }
    public void clearGui() {
        super.clearGui();
    }
    private void createGui() {
        setLayout(new BorderLayout(0, 5));
        setBorder(makeBorder());
        this.setLayout(new BorderLayout(0, 5));
        this.setBorder(this.makeBorder());
        this.add(this.makeTitlePanel(), "North");
        VerticalPanel mainPanel = new VerticalPanel();
        add(mainPanel, "Center");
    }
}
Jmeter MD5插件的更多相关文章
- JMeter Plugin插件配置及远程监控
		下载jmeter plugins 插件: https://jmeter-plugins.org/downloads/all/ 官网建议我们直接下载plugins-manager.jar,然后进行可选择 ... 
- 【JMeter】插件安装
		安装插件的方法有两种,一种是传统的方式,即官网下载,本地配置,重启jmeter.现在有一种快捷的方法可以自定义安装插件-插件管理器 JMeter 插件管理器的使用方法很简单:不要手动安装各种插件,它提 ... 
- JMeter开发插件——图片验证码识别
		我们在性能测试中总会时不时地遭遇到来自于应用系统的各种阻碍,图片验证码就是一类最常见的束缚,登录或交易时需要按照图片中的内容输入正确的验证信息后,数据才可以提交成功,这使得许多性能测试工具只能望而却步 ... 
- 如何为Apache JMeter开发插件(一)
		本文转载于http://blog.csdn.net/column/details/12925.html,作者:xreztento 作者写的很精华,我打算在此系列操作一遍后,加多点截图,便于更多人更快上 ... 
- 如何为Apache JMeter开发插件(二)—第一个JMeter插件
		文章内容转载于:http://lib.csdn.net/article/softwaretest/25700,并且加上个人一些截图 本篇将开启为JMeter开发插件之旅,我们选择以Function(函 ... 
- JMeter扩展插件实现对自定义协议进行支持 转
		本文版权归xmeter.net 所有.欢迎转载,转载请注明出处. 摘要## JMeter本身提供了插件机制,允许第三方扩展JMeter以支持JMeter不支持的协议的测试.本文以扩展一个简单的Apac ... 
- Jmeter websocket插件安装与使用
		Jmeter websocket插件安装与使用 Apache JMeter是Apache组织开发的基于Java的压力测试工具.用于对软件做压力测试,它最初被设计用于Web应用测试,但后来扩展到其他测试 ... 
- Jmeter官方插件实现Dubbo接口测试
		目前主流的分布式框架有Dubbo和SpringCloud, SpringCloud是基于Http协议的分布式框架,Dubbo是基于RPC的分布式框架,Jmeter没有内置对Dubbo接口的支持,很难直 ... 
- 四、Jmeter安装插件
		Jmeter安装插件方法和使用 1-下载Jmeter管理jar包 下载地址:https://jmeter-plugins.org/install/Install/ 2-点击下载 plugins-man ... 
随机推荐
- redis数据类型-集合类型
			集合类型 在集合中的每个元素都是不同的,且没有顺序. 一个集合类型(set)键可以存储至多2 32-1个(相信这个数字对大家来说已经很熟悉了)字符串. 集合类型的常用操作是向集合中加入或删除元素.判断 ... 
- Git分支管理[三]
			标签(linux): git 笔者Q:972581034 交流群:605799367.有任何疑问可与笔者或加群交流 git分支管理命令 git branch #创建分支 git branch -v # ... 
- oracle pl/sql中的循环及if语句
			for循环 /* for循环打印1到10 */ set serveroutput on; declare begin .. loop dbms_output.put_line(i); end loop ... 
- python selenium+phantomjs  alert()弹窗报错
			问题:用selenium+phantomjs 模拟登陆,网页用JavaScript的alert("登陆成功")弹出框,但是用switch_to_alert().accept()报错 ... 
- Spring 当 @PathVariable 遇上 【. # /】等特殊字符
			@PathVariable注解应该不是新鲜东西了Spring3.0就开始有了 URL中通过加占位符把参数传向后台 举个栗子,如下比较要说的内容比较简单就大概齐的写一下 画面侧 $.ajax({ typ ... 
- linux下磁盘占用达到100%了,找不到哪些大文件耗尽了磁盘
			Linux下的根分区使用率100%,但是查看/分区下的目录都不大,没有占用满,这该怎么处理? 重启是肯定有效的,目前处理情况:重新restart应用后,空间释放出来 1.lsof | grep del ... 
- 00_Python面试题_迭代更新
			一.Python是什么类型的语言,以及和其他语言对比 1.Python是一种解释性语言,他和C语言以及C衍生的语言不通,在Python运行之前不需要编译,其他解释语言还有Ruby.PHP. 2.Pyt ... 
- mysql 删匿名帐户
			mysql默认安装,带有匿名帐户 删除它很简单 登录进入msyql并执行以下三行语句: use mysql; delete from user where user=''; flush privile ... 
- C语言深度剖析-笔记
			关键字: C语言关键字32个: 关键字 意 义 auto 声明自动变 ... 
- Java数据结构和算法(九)——高级排序
			春晚好看吗?不存在的!!! 在Java数据结构和算法(三)——冒泡.选择.插入排序算法中我们介绍了三种简单的排序算法,它们的时间复杂度大O表示法都是O(N2),如果数据量少,我们还能忍受,但是数据量大 ... 
