一、HAR文件錄制
fiddler可以將一系列HTTP請求打包檢出存儲成HAR(Http Archive)文件。這個HAR文件是個JSON結構,其中entries下存儲著具體每個HTTP請求的信息,包括請求體、請求方法、請求頭、返回結果等。我們用手機連接電腦fiddler,然后操作客戶端,這樣錄制下來的接口請求完全是從用戶角度進行操作的,所以一定程度上也是基于用戶行為的線上接口的穩定性驗證。錄制過程很簡單,在fiddler中選中要驗證的接口請求(或者全選),點擊File->Export Sessions->selected sessions或者All sessions:
然后選擇默認HTTP ARCHIVE V1.2,點擊Next起個名字保存就可以。
這時候我們可以打開這個HAR文件看看這里面都是什么,可以用Notepad++或者直接拖動HAR文件到fiddler中,查看JSON數據。
具體的HAR文件規范請參考:http://weizhifeng.net/har-12-spec-chinese-edtion.html。
這里有個tip,如果錄制的HAR文件發現某個接口的response中文本內容沒有被完整保存下來,而是顯式”數據太大“。這時候要在錄制前增加一步fiddler的配置,在fiddler界面的左下角黑色命令行處輸入about:config,按下回車。
在右邊出現的配置表中增加一項fiddler.importexport.httparchivejson.maxtextbodylength配置,可設置為10000或者更大的數字:
添加完成后重啟fiddler,再錄制HAR文件,就能看到HTTP請求的響應主體完整的文本信息了。
還有一個tip一定要注意,就是在錄制HAR文件之前,一定要把fiddler菜單欄的Decode選中,否則獲得的responseContent中的內容可不是base64解碼這么簡單的事情了,保存下來的東西不知道是個什么鬼。Decode選中是這樣的狀態,Decode外面有一層藍色的框框,不選中的話是沒有外面的框框的:
二、HAR文件處理、HTTP信息存儲
對HAR文件的處理,首先就要把其中的HTTP的關鍵信息存儲起來。也就是需要一個單獨的類來保存HTTP信息。這里定義了一個HttpInfo類,其中包括的成員變量有:url、請求方法(GET還是POST)、用戶使用的設備、響應主體、響應主體編碼方式、POST請求數據格式、POST請求數據主體。成員函數則是各個成員變量對應的set和get方法。
如何將HAR文件的HTTP的這些信息存儲起來呢?這里我寫了一個單獨的方法來完成這件事情。該方法實現的概要邏輯為:
public List<HttpInfo> HttpInfoSave(){
/*讀取resources中的HAR文件*/
/*HAR文件只有一行,這一行以String類型存儲至HttpArchive變量中*/
/*拆解HttpArchive這個JSON結構體*/
for(i = 0:HttpArchive中entry的數目){
/*獲得這條HTTP請求*/
/*保存請求的url、用戶使用的設備信息、請求方法(GET還是POST)*/
/*保存響應的文本信息*/
/*保存響應的文本編碼信息*/
/*保存POST請求的數據格式信息以及請求主體信息*/
}
/*返回HttpInfo的列表*/
}
三、用戶登陸
之所以要把用戶登錄單獨進行處理,這是因為如果用戶在未登陸的情況下或者使用過期的cookie情況下,有些接口可能返回401請求失敗。所以我們要把登錄請求單獨拿出來進行正確的用戶登錄,才能保證后續的http請求都正常。云閱讀這邊的用戶登錄是https請求,客戶端傳給服務器的包括用戶名以及md5編碼過的用戶密碼(客戶端肯定不會拿用戶的密碼原文給服務器,會將密碼進行不可逆的md5編碼)。登錄成功后要從響應中拿回set-cookie字段保存至全局變量中,便于后面請求時設置請求頭。這里用了一個單獨的方法來完成這件事情:
public void login() throws HttpException, IOException{
HttpClient client = new HttpClient();
PostMethod post = new PostMethod("login url");
JSONObject js = new JSONObject();
js.element("username", "hzsuixiang01@163.com");
js.element("accountType", "0");
js.element("auth", "d554e66e583c8946ad81ba52f6ea468d");
post.setRequestBody(js.toString());
int status = client.executeMethod(post);
System.out.println(status+post.getResponseBodyAsString());
Header[] header = post.getResponseHeaders();
cookies[0] = header[6].getValue(); //已知返回兩個Set-Cookie字段,都要保存下來
cookies[1] = header[7].getValue();}
四、按序執行HTTP請求
前面已經把HAR文件的HTTP請求都分析剝離且保存起來了,而且用戶已經登錄,Cookie字段也已經確定。接下來就是按序執行HAR文件中的HTTP請求了。這里基本沒有什么難點,按照正常的HTTPClient模擬請求的方法來做就可以。唯一需要注意的一點是,當某個請求的encoding-type為base64的時候,要把響應文本內容進行base64解碼,這樣輸出的內容就是可讀的了,便于后續判斷。主要代碼邏輯如下:
for(每一條http請求){
/*獲得具體的HttpInfo信息*/
if(http是get請求){
/*新建HttpClient實例、裝載http請求頭*/
/*發送get請求*/
/*get請求返回數據解析和存儲*/
else{
/*新建HttpClient實例、裝載http請求頭*/
/*發送post請求*/
/*post請求返回數據解析和存儲*/
}}
核心代碼如下:
for(int i = 0;i<HttpInfoList.size();i++){
HttpInfo HttpInfo = HttpInfoList.get(i);
if(HttpInfo.getMethod().equals("GET")){
System.out.println("/********************開始處理第"+i+"條請求了哦*******************************/");
HttpClient client = new HttpClient();
GetMethod get = new GetMethod(HttpInfo.getUrl());
get.addRequestHeader("X-User-Agent",HttpInfo.getUserAgent());
get.addRequestHeader("Cookie", cookies[0]);
get.addRequestHeader("Cookie", cookies[1]);
int status = client.executeMethod(get);
System.out.println(get.getResponseBodyAsString());
if(HttpInfo.getEncoding().equals("base64")){
byte[] content = Base64.decodeBase64(HttpInfo.getResponseContent());
String contentString = new String(content);
System.out.println(contentString); }
else{
System.out.println(HttpInfo.getResponseContent());
System.out.println(HttpInfo.getResponseContent().equals(get.getResponseBodyAsString()));
}
}else{
System.out.println("/********************開始處理第"+i+"條請求了哦*******************************/");
MyClient myClient = new MyClient();
if(HttpInfoList.get(i).getMimeType().equals("application/x-[www-form-urlencoded]{
System.out.println("primitive result: "+HttpInfoList.get(i).getResponseContent());
myClient.doPostWithDataPair(HttpInfoList.get(i).getUrl(), cookies, HttpInfoList.get(i).getParamsPair());
}
else{
System.out.println("primitive result: "+HttpInfoList.get(i).getResponseContent());
myClient.doPostWithDataJson(HttpInfoList.get(i).getUrl(), cookies, HttpInfoList.get(i).getParamsJson());
}
}
}
五、DIFF結果判定
按序執行的HTTP請求的response要與HAR文件中保存的諸請求的response做比較,判定該接口是否出了問題。判定的內容包括:請求響應碼是否一致、響應主體是否相同。