2

Fiddler抓包一键生成代码

 2 years ago
source link: https://www.cnblogs.com/yudongdong/p/15418181.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

首先我们的需求场景是

用Fiddler抓到某个接口调用后,用代码来模拟调用,一般我们写代码会有3个步骤:

  • 1设置http请求相关的参数:header,method,url,cookie等
  • 2设置post的body(如果是post的话需要)
  • 3拿到返回的body(一般我们需要拿到接口的返回体进行解析)

假如这3个步骤的代码全部都能一键生成那该多爽,我终于站在巨人的肩膀上搞定了!

搞定的效果如下图:

imageimage

上面是对于csharp 采用自带的 HttpClient的代码生成演示,还可以针对java kotlin,python,nodejs等

本篇的主要功能都是在FiddlerScript里面完成,主要包含3块扩展

  • 增加自定义右键菜单
  • 增加控制开关
  • 代码获取请求上下文并导出har
  • 使用脚本完成process的封装并调用

1. 增加右键菜单

点中某个Session然后点击右键菜单,选择生成指定语言的代码,这样使用起来最方便,如下图: image

新增右键菜单的扩展方式是 【一个ContextAction+一个function】

    
 public static ContextAction("C#-httpclient", "生成代码")
 function do1(arrSess: Session[]) {  doStar(arrSess, "csharp","httpclient"); }

代表新增一个 一级菜单叫 生成代码,二级菜单叫 "C#-httpclient"

下面的function就是点击需要响应的方法实现,默认是Session数组,因为可以选择多个。

2. 控制开关

前面说有3个步骤,除了第一个步骤是核心的,其他2个步骤都是将json转为实体类定义,是辅助的。所以都设置开关可以人为控制要不要生成这2块的代码

imageimage

新增开关的方式是定义【一个RulesOption+一个对应接收的变量】

 public static RulesOption("关闭请求体转代码", "生成代码")
 var m_DisableReuqest: boolean = false;

代表新增一个 以及菜单叫生成代码,二级菜单叫 "关闭请求体转代码",类型是bool,因为下面对应接收的变量是布尔类型!

3. 通过选中Session拿到整个请求的上下文

上下文包括,请求的各种参数,比如url,header,method,request,response等

imageimage

Fillder有一个api可以导出har文件,这个har格式是谷歌提出来的一个用来描述一个请求的标准定义

关于har格式的详细文档: http://groups.google.com/group/http-archive-specification/

那如何在Fiddler里面将Session导出har呢

imageimageimageimageimageimage

那用代码如何导出呢?


//这种方式为导出到变量 注意是Fiddler 4.6.2.0版本之后支持的
var oExportOptions = FiddlerObject.createDictionary(); 
oExportOptions.Add(“ExportToString”, “true”);
FiddlerApplication.DoExport("HTTPArchive v1.2", oSessions,oExportOptions, null);
//这个就是了
var sOutput: String = oExportOptions[“OutputAsString”];


//这种方式为导出到指定路径
var oExportOptions = FiddlerObject.createDictionary(); 
oExportOptions.Add("Filename", "对应的路径"); 
FiddlerApplication.DoExport("HTTPArchive v1.2", oSessions,oExportOptions, null);

这里我采用了第二种方式,先把选中的Session导出一个har文件,然后将这个har文件作为下一个process的入参,得到我想要结果!

下面隆重介绍根据har来生成请求代码的工具:httpsnippet

开源地址:https://github.com/Kong/httpsnippet

Kong的话有个很有有名的网关想必大家都听说过!

这里我已经把这个程序包装成在windows系统可以独立运行的exe了,可以在文章末尾获取下载链接。

这里我稍微改造了一下代码,把har文件的requestBody和responseBody也提取出来,为了是生成对应的POJO代码做入参.

将json生成实体类POJO这里用了另外一个工具:quicktype

开源地址:https://github.com/quicktype/quicktype

也包装成在windows系统可以独立运行的exe了。

好了,组装一起:

  • 先通过代码生成har文件
  • 然后用httpsnippet生成指定语言的代码,并导出har中的requestBody和responseBody
  • 分别将requestBody和responseBody作为参数让quicktype生成实体类代码

整个的完整代码如下,按照如下步骤copy到fiddler的脚本编辑器中即可:

首先打开脚本编辑器:

imageimage

随便找到一个空白的地方,然后把下面的代码复制进去:


    public static RulesOption("关闭请求体转代码", "生成代码")
 var m_DisableReuqest: boolean = false;

 public static RulesOption("关闭返回体转代码", "生成代码")
 var m_DisableResponse: boolean = false;
   
 public static ContextAction("C#-httpclient", "生成代码")
 function do1(arrSess: Session[]) {  doStar(arrSess, "csharp","httpclient"); }
 public static ContextAction("C#-restsharp", "生成代码")
 function do2(arrSess: Session[]) { doStar(arrSess, "csharp","restsharp"); }

 public static ContextAction("Java-okhttp", "生成代码")
 function do3(arrSess: Session[]) {  doStar(arrSess, "java","okhttp"); }
 public static ContextAction("Java-asynchttp", "生成代码")
 function do4(arrSess: Session[]) {  doStar(arrSess, "java","asynchttp"); }
 public static ContextAction("Java-nethttp", "生成代码")
 function do5(arrSess: Session[]) {  doStar(arrSess, "java","nethttp"); }
 public static ContextAction("Java-unirest", "生成代码")
 function do6(arrSess: Session[]) {  doStar(arrSess, "java","unirest"); }

 public static ContextAction("Kotlin-okhttp", "生成代码")
 function do7(arrSess: Session[]) {  doStar(arrSess, "kotlin","okhttp"); }
   
 public static ContextAction("JavaScript-xhr", "生成代码")
 function do8(arrSess: Session[]) {  doStar(arrSess, "javascript","xhr"); }
 public static ContextAction("JavaScript-jquery", "生成代码")
 function do9(arrSess: Session[]) {  doStar(arrSess, "javascript","jquery"); }
 public static ContextAction("JavaScript-fetch", "生成代码")
 function do10(arrSess: Session[]) {  doStar(arrSess, "javascript","fetch"); }
 public static ContextAction("JavaScript-axios", "生成代码")
 function do11(arrSess: Session[]) {  doStar(arrSess, "javascript","axios"); }
  
 public static ContextAction("Node-native", "生成代码")
 function do12(arrSess: Session[]) {  doStar(arrSess, "node","native"); }
 public static ContextAction("Node-request", "生成代码")
 function do13(arrSess: Session[]) {  doStar(arrSess, "node","request"); }
 public static ContextAction("Node-fetch", "生成代码")
 function do14(arrSess: Session[]) {  doStar(arrSess, "node","fetch"); }
 public static ContextAction("Node-axios", "生成代码")
 function do15(arrSess: Session[]) {  doStar(arrSess, "node","axios"); }   
 public static ContextAction("Node-unirest", "生成代码")
 function do16(arrSess: Session[]) {  doStar(arrSess, "node","unirest"); } 
 
 public static ContextAction("Python3-http.client", "生成代码")
 function do17(arrSess: Session[]) {  doStar(arrSess, "python","python3"); }
 public static ContextAction("Python-requests", "生成代码")
 function do18(arrSess: Session[]) {  doStar(arrSess, "python","requests"); }
   
 public static ContextAction("ObjectiveC-nsurlsession", "生成代码")
 function do19(arrSess: Session[]) {  doStar(arrSess, "objc","nsurlsession"); }

 public static ContextAction("Ruby-net::http", "生成代码")
 function do20(arrSess: Session[]) {  doStar(arrSess, "ruby","native"); }

 public static ContextAction("Swift-nsurlsession", "生成代码")
 function do21(arrSess: Session[]) {  doStar(arrSess, "swift","nsurlsession"); }
   
 public static ContextAction("powershell-webrequest", "生成代码")
 function do22(arrSess: Session[]) {  doStar(arrSess, "powershell","webrequest"); }
 public static ContextAction("powershell-restmethod", "生成代码")
 function do23(arrSess: Session[]) {  doStar(arrSess, "powershell","restmethod"); }

 public static ContextAction("Shell-curl", "生成代码")
 function do24(arrSess: Session[]) {  doStar(arrSess, "shell","curl"); }
 public static ContextAction("Shell-httpie", "生成代码")
 function do25(arrSess: Session[]) {  doStar(arrSess, "shell","httpie"); }
 public static ContextAction("Shell-wget", "生成代码")
 function do26(arrSess: Session[]) {  doStar(arrSess, "shell","wget"); }
  
 public static ContextAction("Go-NewRequest", "生成代码")
 function do27(arrSess: Session[]) { doStar(arrSess, "go","native"); }
   
 public static ContextAction("Clojure-clj_http", "生成代码")
 function do28(arrSess: Session[]) { doStar(arrSess, "clojure","clj_http"); }

 public static ContextAction("C-Libcurl", "生成代码")
 function do29(arrSess: Session[]) { doStar(arrSess, "c","libcurl"); }
 
 public static ContextAction("PHP-curl", "生成代码")
 function do30(arrSess: Session[]) {  doStar(arrSess, "php","curl"); }
 public static ContextAction("PHP-http1", "生成代码")
 function do31(arrSess: Session[]) {  doStar(arrSess, "php","http1"); }
 public static ContextAction("PHP-http2", "生成代码")
 function do32(arrSess: Session[]) {  doStar(arrSess, "php","http2"); }  
  
 public static function doStar(oSessions: Session[], target: String,client:String) {
     //注意看这里,请下载我给的这2个exe并替换成你电脑中正确的目录
  var httpsnippet = "E:\\workspace\\github\\test\\httpsnippet.exe";
  var quicktype = "E:\\workspace\\github\\test\\quicktype.exe";
  var oExportOptions = FiddlerObject.createDictionary(); 
  var tempPath2 = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "fiddler.har");
  if(System.IO.File.Exists(tempPath2)){
   System.IO.File.Delete(tempPath2); 
  }
  var tempPath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "fiddler.json");
  if(System.IO.File.Exists(tempPath)){
   System.IO.File.Delete(tempPath); 
  }
  var tempRequestBodyPath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "fiddler_requestBody.json");
  if(System.IO.File.Exists(tempRequestBodyPath)){
   System.IO.File.Delete(tempRequestBodyPath); 
  }
  var tempResponseBodyPath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "fiddler_responseBody.json");
  if(System.IO.File.Exists(tempResponseBodyPath)){
   System.IO.File.Delete(tempResponseBodyPath); 
  }
  oExportOptions.Add("Filename", tempPath2); 
  FiddlerApplication.DoExport("HTTPArchive v1.2", oSessions,oExportOptions, null);  
  System.IO.File.Move(tempPath2, tempPath);
  if(!System.IO.File.Exists(tempPath)){
   MessageBox.Show("生成代码失败", "No action");
   return;  
  }
  var rtPath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "fiddler_rt");
  if(System.IO.Directory.Exists(rtPath))System.IO.Directory.Delete(rtPath,true);
  if(!doProcess(httpsnippet, "\""+tempPath+"\" -t "+target+" -c "+client+" -o " + "\""+rtPath+"\"")){
   MessageBox.Show("生成代码错误", "No action");
   return;  
  }
  var file = System.IO.Directory.GetFiles(rtPath);
  if(file.Length!=1){
   MessageBox.Show("生成代码错误", "No action");
   return; 
  }
  var json = System.IO.File.ReadAllText(file[0]);
  System.IO.File.Delete(file[0]);
  var rtPath1 = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "fiddler_request_body");
  if(System.IO.File.Exists(rtPath1))System.IO.File.Delete(rtPath1);
  if(!m_DisableReuqest && System.IO.File.Exists(tempRequestBodyPath)){
  
   json += getJsonCode(quicktype,tempRequestBodyPath,rtPath,rtPath1,target,"FiddlerRequest");
  }
  rtPath1 = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "fiddler_response_body");
  if(System.IO.File.Exists(rtPath1))System.IO.File.Delete(rtPath1);
  if(!m_DisableResponse && System.IO.File.Exists(tempResponseBodyPath)){
   json += getJsonCode(quicktype,tempResponseBodyPath,rtPath,rtPath1,target, "FiddlerReponse"); 
  } 
  
  Clipboard.SetText(json);
  MessageBox.Show("代码生成成功,已复制到剪贴板"); 
 }
  
 static function getJsonCode(file: String,tempRequestBodyPath:String,rtPath:String,rtPath1:String,target:String,type:String): String {
  var json = "";
  var tmp1 = "";
  if(target == 'csharp'){
   tmp1 = "--quiet --telemetry disable --features just-types --array-type list --no-check-required --namespace \"Fiddlers\" --lang \"" + target + "\" --top-level \""+type+"Model\" \"" + tempRequestBodyPath + "\"" +" -o " + "\""+rtPath1+"\"";
  }
  else if(target == 'kotlin'){
   tmp1 = "--quiet --telemetry disable --framework just-types --lang \"" + target + "\" --top-level \""+type+"Model\" \"" + tempRequestBodyPath + "\"" +" -o " + "\""+rtPath1+"\"";
  }
  else if(target == 'java'){
   tmp1 = "--quiet --telemetry disable --array-type list --just-types --package \"Fiddlers\" --lang \"" + target + "\" --top-level \""+type+"Model\" \"" + tempRequestBodyPath + "\"" +" -o " + "\""+rtPath+"\\test"+"\"";
    
  }
  else {
   tmp1 = "--telemetry disable --just-types  --lang \"" + target + "\" --top-level \""+type+"Models\" \"" + tempRequestBodyPath + "\"" +" -o " + "\""+rtPath1+"\""; 
  }
   
  doProcess(file, tmp1)
  if(System.IO.File.Exists(rtPath1)){
   json += "\r\n//"+type+"-POJO\r\n" + System.IO.File.ReadAllText(rtPath1).Replace("package quicktype","");
  }
   
  if(target == 'java'){
   var javaFiles = System.IO.Directory.GetFiles(rtPath,"*.java"); 
   if(javaFiles.Length>0){
    json += "\r\n//"+type+"-POJO\r\n" ;
    for (var i:int = 0; i<javaFiles.Length; i++)
    {
     json += System.IO.File.ReadAllText(javaFiles[i]).Replace("package Fiddlers;","")
     System.IO.File.Delete(javaFiles[i]);
    }
   }
  }
  return json;
 }
   
 static function doProcess(file: String,paramsList:String): Boolean {
  var process = new System.Diagnostics.Process();
  process.StartInfo.FileName = file;
  process.StartInfo.Arguments = paramsList;
  process.StartInfo.CreateNoWindow = true;
  process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
  process.StartInfo.UseShellExecute = false;
  process.StartInfo.Verb = "runas";
  process.StartInfo.RedirectStandardError = true;
  process.StartInfo.RedirectStandardOutput = true;
  process.Start();
  process.WaitForExit();
  process.Dispose(); 
  return true;
 }

然后下载:httpsnippet和quicktype这2个可执行文件。获取下载地址的方法:关注文末公众号后发送文本 :Fiddler ,会告诉你百度网盘链接!

下载zip包后然后把这2个文件解压到你的电脑的某个目录。

在回到脚本中找到 doStar 方法中修改成正确的目录。

Enjoy!!!

关注公众号一起学习

472365-20210606154607111-1839147492.png


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK