前言
埋点是业务测试过程中,算是一个比较繁琐的环节,一般情况下检查埋点,可以通过网络抓包,或者埋点数据落库去检查数据库去校验,但是我觉得这些都比较麻烦,对我这种比较懒的人来说,简直不太友好,基于这些想在网络抓包的时候可以再做一层过滤对请求做处理,以表格的形式展示埋点信息,让我可以很清晰的看清埋点是否有上报
一、效果图
别的不说先上图看看最终的成果吧。
主要功能,从图中也可以看出,就是抓取指定的URL,然后对URL进行解析,取出埋点参数,展示到表单中
二、如何实现的?
1.开发语言C#
C#是好久没有碰到过的东西了,大学的时候也是简单的接触过,不过为了让自己更加懒一点,还是感觉恶补一波
主要核心部分代码
代码如下(示例):
using Fiddler;
using System;
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Threading;
using System.Text.RegularExpressions;
namespace FiddlerExtension
{
public class Class1 : IAutoTamper
{
private TabPage tabPage; //创建插件的选项卡页
private UserControl1 myCtrl; //MyControl自定义控件
private string filePath;
//private FileStream fs;
//private StreamWriter sw;
private StringBuilder contentSBTrue;
private StringBuilder contentSBFalse;
private Boolean isUseSBFlag;
private int currentCount;
public const int WRITE_FILE_THRESHOLD = 1;
public Class1()
{
//构造函数中实例化对象
this.tabPage = new TabPage("MyFiddlerExtension");//选项卡的名字为Test
this.myCtrl = new UserControl1();
filePath = AppDomain.CurrentDomain.BaseDirectory + "output" + ".csv";
//StringBuilder sb = new StringBuilder();
//fs = new FileStream(path, FileMode.Create);
//sw = new StreamWriter(fs);
contentSBTrue = new StringBuilder();
contentSBFalse = new StringBuilder();
isUseSBFlag = true;
currentCount = 0;
}
public void OnLoad()
{
//将用户控件添加到选项卡中
this.tabPage.Controls.Add(this.myCtrl);
//为选项卡添加icon图标,这里使用Fiddler 自带的
this.tabPage.ImageIndex = (int)Fiddler.SessionIcons.Timeline;
//将tabTage选项卡添加到Fidder UI的Tab 页集合中
FiddlerApplication.UI.tabsViews.TabPages.Add(this.tabPage);
}
public void OnBeforeUnload()
{
}
public static string GetValue(string str, string s, string e) //截取字符串指定区间
{
Regex rg = new Regex("(?<=(" + s + "))[.\\s\\S]*?(?=(" + e + "))", RegexOptions.Multiline | RegexOptions.Singleline);
return rg.Match(str).Value;
}
// Called before the user can edit a request using the Fiddler Inspectors
public void AutoTamperRequestBefore(Session oSession)
{
// this.myCtrl.textBox1.Text += oSession.fullUrl + "\r\n";
// 过滤满足条件的host
if (this.myCtrl.Filter != "")
{
string url = oSession.fullUrl;
foreach (string filterString in this.myCtrl.FilterArray)
{
if (url.Contains(filterString))
{
ListViewItem item = new ListViewItem(this.myCtrl.listView1.Items.Count + "");
//item.SubItems.Add(oSession.host); // 加入host
//item.SubItems.Add(oSession.fullUrl); // 加入fullUrl
item.SubItems.Add(System.Web.HttpUtility.UrlDecode(GetValue(url, "&pageId=", "&defined_name")));//解析参数pageId
item.SubItems.Add(System.Web.HttpUtility.UrlDecode(GetValue(url, "&defined_name=", "&defined_value")));//解析参数defined_name
item.SubItems.Add(System.Web.HttpUtility.UrlDecode(GetValue(url, "&defined_value=", "&deviceInfo")));//解析参数defined_value
item.SubItems.Add(oSession.id + "");// 加入packetNo
item.SubItems.Add(DateTime.Now.ToString()); // 加入time
this.myCtrl.listView1.Items.Add(item);
string temp = oSession.id + "," + oSession.fullUrl + "," + DateTime.Now.ToString(); // 取出url的数据进行保存
currentCount++;
//sw.WriteLine(temp);
//sw.Flush();
if (isUseSBFlag) // 写出到contentSBTrue中
{
AppendSB(contentSBTrue, temp);
}
else // 写出到contentSBFalse中
{
AppendSB(contentSBFalse, temp);
}
}
}
}
}
/// <summary>
/// 写入到StringBuilder中,满足一定条件后写出到文件中
/// </summary>
/// <param name="contentSB">StringBuilder</param>
/// <param name="temp">追加到contentSB的string</param>
/// <returns></returns>
private void AppendSB(StringBuilder contentSB, string temp)
{
contentSB.AppendLine(temp);
if (currentCount >= WRITE_FILE_THRESHOLD)
{
isUseSBFlag = !isUseSBFlag;
// 线程统一写出到文件中
currentCount = 0;
Thread thexp = new Thread(() => WriteToFile(ref contentSB, this.filePath)) { IsBackground = true };
thexp.Start();
}
}
/// <summary>
/// 写入记事本
/// </summary>
/// <param name="contentSB">写出的内容</param>
/// <param name="filePath">文件路径(含文件名)</param>
/// <returns></returns>
private static void WriteToFile(ref StringBuilder contentSB, string filePath)
{
try
{
File.AppendAllText(filePath, contentSB.ToString(), Encoding.UTF8);
//MessageBox.Show("已保存完毕,路径:" + filePath);
contentSB.Remove(0, contentSB.Length); // 清空
}
catch
{
//MessageBox.Show("遇到问题,未保存到文件中");
}
}
// Called after the user has had the chance to edit the request using the Fiddler Inspectors, but before the request is sent
public void AutoTamperRequestAfter(Session oSession) { }
// Called before the user can edit a response using the Fiddler Inspectors, unless streaming.
public void AutoTamperResponseBefore(Session oSession) { }
// Called after the user edited a response using the Fiddler Inspectors. Not called when streaming.
public void AutoTamperResponseAfter(Session oSession) { }
// Called Fiddler returns a self-generated HTTP error (for instance DNS lookup failed, etc)
public void OnBeforeReturningError(Session oSession) { }
}
}
2.插件界面部分代码
代码如下(示例):
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace FiddlerExtension
{
public partial class UserControl1 : UserControl
{
private string filter = "";
private string[] filterArray;
private bool isBeginFilter = false;
public UserControl1()
{
InitializeComponent();
}
public string Filter
{
get
{
return filter;
}
set
{
filter = value;
}
}
public string[] FilterArray
{
get
{
return filterArray;
}
set
{
filterArray = value;
}
}
private void button1_Click_1(object sender, EventArgs e)
{
if (!isBeginFilter) // beginFilter
{
isBeginFilter = !isBeginFilter;
Filter = this.textBox2.Text;
// 拆分成字符串数组
FilterArray = Filter.Split('|');
this.button1.Text = "停止捕获";
}
else
{
isBeginFilter = !isBeginFilter;
Filter = "";
this.button1.Text = "开始捕获";
}
}
private void button2_Click(object sender, EventArgs e)
{
// 把当前listview中的数据保存到output.txt中
if (this.listView1.Items.Count == 0)
{
MessageBox.Show("列表为空!");
}
else
{
List<string> list = new List<string>();
foreach (ListViewItem item in this.listView1.Items)
{
string temp = item.SubItems[1].Text+"," +item.SubItems[2].Text+","+ item.SubItems[3].Text; // 取pageId,defined_name,defined_value
list.Add(temp);
}
Thread thexp = new Thread(() => export(list)) { IsBackground = true };
thexp.Start();
}
}
private void button3_Click(object sender, EventArgs e)
{
// 把当前listview中的数据保存到output.txt中
if (this.listView1.Items.Count == 0)
{
MessageBox.Show("列表已空,无需再清空!");
}
else
{
this.listView1.Items.Clear();
MessageBox.Show("列表已清空!");
}
}
private void export(List<string> list)
{
string path = AppDomain.CurrentDomain.BaseDirectory + "url_" + Guid.NewGuid().ToString() + ".csv";
StringBuilder sb = new StringBuilder();
foreach (string urlString in list)
{
sb.AppendLine(urlString);
}
System.IO.File.WriteAllText(path, sb.ToString(), Encoding.UTF8);
MessageBox.Show("已保存完毕,路径:" + path);
}
}
}
总结
路漫漫,其修远兮。第一次写插件的小记录