dubbo接口测试转换成http便捷请求

背景

大部分测试dubbo接口,都是使用Jmeter工具进行测试,需要把jar包下载下来,再根据dubbo接口的传值方法进行测试,对于这一过程及其不方便,有时候会因为dubbo版本与Jmeter插件版本不兼容,导致测试无法进行下去,踩坑较多测试效率较低;为此,本文分享一个dubbo接口测试小工具,大大提高效率!

实现方案

Python + fastapi web框架 + Telnet库

方案原理

dubbo提供了telent命令查看服务,脚本模拟Telnet命令进行dubbo接口测试,通过web框架对Telnet命令进行包装,发送Telnet命令之后,解析数据,通过http接口返回

源码分析

  1. Telnet分解(总结了dubbo接口大致传参类型,如遇特殊的,可联系我)
    def invoke(self, service_name, method_name, arg):
        #自定义对象传参
        if isinstance(arg, dict) and arg:
            command_str = "invoke {0}.{1}({2})".format(
                service_name, method_name, json.dumps(arg))
        #集合对象传参
        elif isinstance(arg, list) and arg:
            command_str = "invoke {0}.{1}({2})".format(
                service_name, method_name, json.dumps(arg))
        #无需对象传值
        elif isinstance(arg, dict) and not arg:
            command_str = "invoke {0}.{1}()".format(
                service_name, method_name)
        #枚举值类型传参
        else:
            command_str = "invoke {0}.{1}({2})".format(
                service_name, method_name, arg)
        data = self.command(command_str)
        try:
            # 字节数据解码 utf8
            data = data.decode("utf-8").split('\n')[0].strip()
        except BaseException:
            # 字节数据解码 gbk
            data = data.decode("gbk").split('\n')[0].strip()
        return data
  1. 模拟command控制台提交
    def command(self, str_=""):
        # 模拟cmd控制台 dubbo>invoke ...
        if self.conn :
            self.conn.write(str_.encode() + b'\n')
            data = self.conn.read_until(self.prompt.encode())
            return data
        else:
            return False

3.支持dubbo接口查询(根据IP地址、端口、服务名查询到对应方法名下的传参类型)

    def ls_invoke(self, service_name):
        command_str = "ls -l {0}".format(service_name)
        data = self.command(command_str)
        if "No such service" in data.decode("utf-8"):
            return False
        else:
            data = data.decode("utf-8").split('\n')
            key = ['methodName', 'paramType','type']
            dubbo_list = []
            for i in range(0, len(data) - 1):
                value = []
                dubbo_name = data[i].strip().split(' ')[1]
                method_name = re.findall(r"(.*?)[(]", dubbo_name)[0]
                value.append(method_name)
                paramType = re.findall(r"[(](.*?)[)]", dubbo_name)[0]
                paramTypeList = paramType.split(',')
                if len(paramTypeList) ==1:
                    paramTypeList = paramTypeList[0]
                value.append(paramTypeList)
                if 'java.lang' in paramType or 'java.math' in paramType:
                    value.append(0)
                elif not paramType:
                    value.append(1)
                elif 'List' in paramType:
                    value.append(2)
                else:
                    value.append(3)
                dubbo_list.append(dict(zip(key, value)))
            return dubbo_list

4.view源码--dubboList

@router.post('/dubboList', name='dubbo列表接口')
async def dubboList(data: DubboListBody):
    host,port = data.url.split(":")
    service_name = data.serviceName
    method_name = data.methodName
    conn = BmDubbo(host, port)
    status = conn.command("")
    #判断是否连接成功
    if status:
        #传入方法名,查询对应方法名的传值类型
        if method_name:
            param_data = conn.param_data(service_name, method_name)
            #判断方法是否存在
            if param_data:
                res_data = {'responseCode': 200, 'responseMsg': "请求成功"}
                dubbo_list = {'responseData': param_data}
                res_data.update(dubbo_list)
                return res_data
            #不存在返回报错
            else:
                return {'responseCode': 301, 'responseMsg': "找不到对应的serviceName"}
        #不传,直接返回服务下所有的数据
        else:
            response_data = conn.ls_invoke(service_name)
            if response_data:
                res_data = {'responseCode': 200, 'responseMsg': "请求成功"}
                dubbo_list = {'responseData':response_data}
                res_data.update(dubbo_list)
                return res_data
            else:
                return {'responseCode': 301, 'responseMsg': "找不到对应的serviceName"}

    #连接不成功返回报错
    else:
        return {'responseCode': 302, 'responseMsg': "dubbo服务连接出错"}

5.view源码--dubboInvoke

@router.post('/dubbo', name='dubbo业务请求接口')
async def dubboInvoke(data: DubboInvokeBody):
    host,port = data.url.split(":")
    service_name = data.serviceName
    method_name = data.methodName
    boby = data.data
    conn = BmDubbo(host, port)
    status = conn.command("")
    if status:
        # 根据服务名和方法名,返回param方法名和类型
        param_data = conn.param_data(service_name, method_name)
        if param_data:
            type = param_data['type']
            param = param_data['paramType']
            # 传参类型为枚举值方法
            if type == 0:
                l_data = [v for v in boby.values()]
                l_data = str(l_data)
                boby = l_data[1:-1]
            # 无需传参
            elif type == 1:
                boby = boby
            # 传参类型为集合对象
            elif type == 2:
                for k, v in boby.items():
                    if isinstance(v, list):
                        boby = v
                        break
            # 传参类型为自定义对象
            else:
                boby.update({"class": param})
            response_data = conn.invoke(service_name, method_name, boby)
            try:
                response_data = json.loads(response_data)
            except Exception as e:
                res_data = {'responseCode': 207, 'responseMsg': "dubbo接口请求异常"}
                res_data.update({'responseData':response_data})
                return res_data
            return response_data
        else:
            return {'responseCode': 301, 'responseMsg': "找不到对应的serviceName"}

    else:
        return {'responseCode': 302, 'responseMsg': "dubbo服务连接出错"}

使用教程

  • pip install requirements.txt
  • 右键运行main文件
  • 访问http://127.0.0.1:5000/api/xxx 即可开始测试dubbo接口
  • 具体传参可看dubbo接口文档
  • 基于fastapi,将dubbo接口转换成便捷的http接口测试
  • 优点:等你来发掘
  • 缺点/bug:等你来发掘

dubbo接口文档

1.查询服务名下的所有方法

接口地址

  • 说明:根据dubbo接口地址和dubbo接口服务名,查询服务名下的所有方法
  • 地址:/api/dubboList
  • 方法:POST

请求头

序号 类型 说明
1 Content-Type application/json JSON 格式

请求体

序号 键值 类型 说明
1 url String dubbo接口地址,IP:端口
2 serviceName String 对应的服务名
3 methodName String 服务名下对应的方法名

请求体示例

{
    "url": "xxx.xxx.xx.xx:20880",
    "serviceName": "cn.com.xxx.mallerp.api.xxxx.xxxx"
}

返回体

序号 键值 类型 说明
1 responseCode Int 返回code
2 responseMsg String 返回信息
3 responseData Array data数组
4 - type int 0-枚举值,1-无需传参<br />2- 集合对象,3-自定义对象
- paramType string Java传值类型
- methodName string 方法名

返回值示例(成功)

{
    "responseCode": 200,
    "responseMsg": "请求成功",
    "responseData": [
        {
            "methodName": "xxxxxx",
            "paramType": "java.util.HashMap",
            "type": 3
        },
        {
            "methodName": "xxxxxx",
            "paramType": [
                "java.lang.String",
                "java.lang.String",
                "java.lang.String",
                "java.lang.Integer",
                "java.lang.Integer"
            ],
            "type": 0
        },
        {
            "methodName": "xxxxxx",
            "paramType": "",
            "type": 1
        },
        {
            "methodName": "xxxxxx",
            "paramType": "java.util.List",
            "type": 2
        }
    ]
}

返回值示例(失败)

{
    "responseCode": 500,
    "responseMsg": "相应的报错信息"
}

2.dubbo接口-业务接口

接口地址

  • 说明:根据dubbo接口地址和dubbo接口服务名,方法名,参数值实现dubbo接口逻辑
  • 地址:/api/dubbo
  • 方法:POST

请求头

序号 类型 说明
1 Content-Type application/json JSON 格式

请求体

序号 键值 类型 说明
1 url string dubbo接口地址,IP:端口
2 serviceName string 服务名
3 methodName string 方法名
4 data object 传值4种情况,具体看示例

请求体示例 -- 原生对象或者自定义对象传参

{
    "url": "xxx.xxx.xx.xx:20880",
    "serviceName": "cn.com.xxx.mallerp.api.xxxx.xxxx",
    "methodName": "xxxxxx",
    "data": {        //data传入对应的业务json数据
        "productStoreQueryDTOS": [
            {
                "productNoNumDTOList": [
                    {
                        "num": 13,
                        "productNo": "10000620"
                    },
                    {
                        "num": 13,
                        "productNo": "10000014"
                    }
                ],
                "storeCode": "4401S1389"
            }
        ]
    }
}

请求体示例 -- 枚举值类型传参

{
    "url": "xxx.xxx.xx.xx:20880",
    "serviceName": "cn.com.xxx.mallerp.api.xxxx.xxxx",
    "methodName": "login",
    "data": {         //格式为json,顺序必须按照dubbo接口枚举值传参顺序,注意是否为int还是string
        "account":"80563855",
        "password":"3fd6ebe43dab8b6ce6d033a5da6e6ac5"
    }
}

请求体示例 -- 方法名无需传参

{
    "url": "xxx.xxx.xx.xx:20880",
    "serviceName": "cn.com.xxx.mallerp.api.xxxx.xxxx",
    "methodName": "xxxxxx",
    "data":{}      //传入空对象
}

请求体示例 --集合对象传参

{
    "url": "xxx.xxx.xx.xx:20880",
    "serviceName": "cn.com.xxx.mallerp.api.xxxx.xxxx",
    "methodName": "xxxxxx",
    "data":{
        "empList": [
            "30000445",
            "30000444"
        ]
    } //传入对象,里面嵌套数组
}

返回值示例(成功)只展示其中一种

{
    "responseData": "dubbo接口返回什么,就返回什么"
}

返回值示例(失败)

{
    "responseCode": 500,
    "responseMsg": "相应的报错信息"
}

项目地址:dubbo_fastapi

©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容