• Fiddler抓包一键生成代码


    首先我们的需求场景是

    用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呢

    image image image image imageimage

    那用代码如何导出呢?

    
    //这种方式为导出到变量 注意是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 += "
    //"+type+"-POJO
    " + System.IO.File.ReadAllText(rtPath1).Replace("package quicktype","");
      }
       
      if(target == 'java'){
       var javaFiles = System.IO.Directory.GetFiles(rtPath,"*.java"); 
       if(javaFiles.Length>0){
        json += "
    //"+type+"-POJO
    " ;
        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 方法中修改成正确的目录。

    (经过群友反应:无法在win7系统上使用,在win7系统需要设置一个环境变量(NODE_SKIP_PLATFORM_CHECK 值为 1),如下图

     

    Enjoy!!!

    关注公众号一起学习

     


    如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,转载文章之后须在文章页面明显位置给出作者和原文连接,谢谢。
  • 相关阅读:
    RPC、HTTP、IDL
    秋招拿了7个offer,分享一些反思和经验
    “功能测试”到“测试开发”升级之路
    Github最全买房租房攻略,火了!
    王垠:怎样尊重一个程序员?
    为什么曾经优秀的人突然变得平庸?
    你这么努力,为什么能力提升还这么慢?
    打工人到什么状态,就可以离职了?
    怎样才能迅速晋升?
    如何做个优秀的经理?
  • 原文地址:https://www.cnblogs.com/yudongdong/p/15418181.html
Copyright © 2020-2023  润新知