MitmProxy使用:流量劫持与入库,流量回放

 

流量截取与入库

我们需要先定义和初始化流量截取后存储的表结构,这里我们采用 peewee 这个 ORM 库,进行操作。
更多操作可参考:
http://docs.peewee-orm.com/en/latest/peewee/quickstart.html

from peewee import *
import datetime
//可以考虑通过 docker 快速搭建 Mysql 服务
db = MySQLDatabase("mitmproxy", host="172.17.0.2", port=3306, user="root", passwd="xxxx")
db.connect()

class HttpRecords(Model):
    //定义了三个字段,id, http 请求记录,时间戳
    id = BigAutoField(primary_key=True)
    httprecord = TextField()
    timestamps = DateTimeField(default=datetime.datetime.utcnow)

    class Meta:
        database = db

接下来编写我们的插件脚本,用于拦截请求,并且写入到我们定义好的数据库表中,如下:

//关注接口(get 请求)
get_url = "https://frodo.douban.com/api/v2/user/91807076/following"

//发表说说的接口(post 请求)
post_url = "https://frodo.douban.com/api/v2/status/create_status?loc_id=118282"
httprecord = {}
url_list = [get_url, post_url]

def parser_data(query):
    data = {}
    for key, value in query.items():
        data[key] = value
    return data

class HttpRecord:
    @concurrent
    def request(self, flow: http.HTTPFlow):
        //这里可以根据自身业务需求,拦截特定域名下的请求(这里为了方便演示,特地指定了两个接口地址)
        if flow.request.pretty_url.startswith(get_url):
            httprecord['method'] = flow.request.method
            httprecord['scheme'] = flow.request.scheme
            httprecord['url'] = flow.request.pretty_url
            httprecord['request_headers'] = {}
            for item in flow.request.headers:
                httprecord['request_headers'][item] = flow.request.headers[item]
            httprecord['get_data'] = parser_data(flow.request.query)
            httprecord['post_data'] = parser_data(flow.request.urlencoded_form)

    @concurrent
    def response(self, flow: http.HTTPFlow):
        if flow.request.pretty_url.startswith(get_url):
            httprecord['status_code'] = flow.response.status_code
            httprecord['response_headers'] = {}
            for item in flow.response.headers:
                httprecord['response_headers'][item] = flow.response.headers[item]
            httprecord['response_content'] = flow.response.get_text()

            # 插入数据库
            record = HttpRecords(httprecord=httprecord)
            record.save()

addons = [
    HttpRecord()
]

检查数据库表,看是否插入成功,如下:

流量回放进行接口测试

从数据库中查询请求记录,并按不同请求方法,e.g. get/post 进行分类;
通过 request 网络请求库,进行重新回放请求接口;
引入 Pytest 测试框架,加入断言,进行组织测试用例的执行,具体代码可参考如下:

import demjson
import requests
from replay.httpmodel import HttpRecords
import pytest

class TestInterface:
    get_http = []
    post_http = []
    def setup_class(self):
        # 从数据库获取流量记录(前置处理操作)
        self.httprecords = HttpRecords.select()
        for item in self.httprecords:
            data = demjson.decode(item.httprecord)
            if data['method'] == "GET":
                self.get_http.append(data)
            elif data['method'] == "POST":
                self.post_http.append(data)
            else:
                ...
        # 初始化请求 session
        self.session = requests.session()

    def testReplayGet(self):
        """
         测试回放 Get 请求
        """
        for i in range(len(self.get_http)):
            res = self.session.get(url=self.get_http[i]['url'], headers=self.get_http[i]['request_headers'], data=self.get_http[i]['get_data'])
            //这里主要是断言了响应状态码,在实际业务中,我们还需要断言返回格式及校验核心字段。
            assert res.status_code == 200

    def testRelayPost(self):
        """
        测试回放 Post 请求
        """
        for i in range(len(self.post_http)):
            res = self.session.post(url=self.post_http[i]['url'], headers=self.post_http[i]['request_headers'], data=self.post_http[i]['post_data'])
            assert res.status_code == 200

if __name__ == '__main__':
    pytest.main(["--html=report.html --self-contained-html", "interfacereplay.py"])

查看测试报告
get 和 post 请求分别回放测试成功:

 

posted @ 2020-11-07 14:36  -零  阅读(1715)  评论(1编辑  收藏  举报