首先我們的需求場景是
用Fiddler抓到某個介面呼叫後,用程式碼來模擬呼叫,一般我們寫程式碼會有3個步驟:
-
1設定http請求相關的引數:header,method,url,cookie等 -
2設定post的body(如果是post的話需要) -
3拿到返回的body(一般我們需要拿到介面的返回體進行解析)
假如這3個步驟的程式碼全部都能一鍵生成那該多爽,我終於站在巨人的肩膀上搞定了!
搞定的效果如下圖:
上面是對於csharp 採用自帶的 HttpClient的程式碼生成演示,還可以針對java kotlin,python,nodejs等
本篇的主要功能都是在FiddlerScript裡面完成,主要包含3塊擴充套件
-
增加自定義右鍵選單 -
增加控制開關 -
程式碼獲取請求上下文並匯出har -
使用指令碼完成process的封裝並呼叫
1. 增加右鍵選單
點中某個Session然後點選右鍵選單,選擇生成指定語言的程式碼,這樣使用起來最方便,如下圖:
新增右鍵選單的擴充套件方式是 【一個ContextAction+一個function】
例如:
public static ContextAction("C#-httpclient", "生成程式碼")
function do1(arrSess: Session[]) { doStar(arrSess, "csharp","httpclient"); }
代表新增一個 一級選單叫 生成程式碼,二級選單叫 "C#-httpclient"
下面的function就是點選需要響應的方法實現,預設是Session陣列,因為可以選擇多個。
2. 控制開關
前面說有3個步驟,除了第一個步驟是核心的,其他2個步驟都是將json轉為實體類定義,是輔助的。所以都設定開關可以人為控制要不要生成這2塊的程式碼
如下圖:
新增開關的方式是定義【一個RulesOption+一個對應接收的變數】
public static RulesOption("關閉請求體轉程式碼", "生成程式碼")
var m_DisableReuqest: boolean = false;
代表新增一個 以及選單叫生成程式碼,二級選單叫 "關閉請求體轉程式碼",型別是bool,因為下面對應接收的變數是布林型別!
3. 通過選中Session拿到整個請求的上下文
上下文包括,請求的各種引數,比如url,header,method,request,response等
Fillder有一個api可以匯出har檔案,這個har格式是谷歌提出來的一個用來描述一個請求的標準定義
關於har格式的詳細文件: http://groups.google.com/group/http-archive-specification/
那如何在Fiddler裡面將Session匯出har呢
那用程式碼如何匯出呢?
//這種方式為匯出到變數 注意是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的指令碼編輯器中即可:
首先開啟指令碼編輯器:
隨便找到一個空白的地方,然後把下面的程式碼複製進去:
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!!!
關注公眾號一起學習