干貨!接口測(cè)試中模擬post四種請(qǐng)求數(shù)據(jù)


一、背景介紹

在日常的接口測(cè)試工作中,模擬接口請(qǐng)求通常有兩種方法,fiddler模擬和HttpClient模擬。

Fiddler是一個(gè)簡(jiǎn)單的http協(xié)議調(diào)試代理工具,它界面友好,易于操作,是模擬http請(qǐng)求的利器之一。
而我們常說(shuō)的HttpClient工具包,追根溯源是Apache基金的HttpComponent項(xiàng)目的一個(gè)組成部分。HttpComponent有三個(gè)主要組成部分,分別是HttpCore、HttpClient以及AsynchHttpClient。按照HttpComponent官網(wǎng)的介紹,HttpCore是底層的HTTP傳輸組件,用最小的內(nèi)存來(lái)實(shí)現(xiàn)模擬客戶端和服務(wù)器端的Http請(qǐng)求。HttpClient則是基于HttpCore實(shí)現(xiàn)的Http請(qǐng)求模擬代理, 可以用來(lái)提供高效的、最新的、功能豐富的支持HTTP協(xié)議的客戶端編程工具包。Asynch HttpClient也是基于HttpCore的,顧名思義則是用于處理大量并發(fā)請(qǐng)求時(shí)的http代理。不同格式的數(shù)據(jù)通過(guò)這兩種模擬方法的處理方式不同。

在接口測(cè)試中,接口通常是get請(qǐng)求或者post請(qǐng)求。get請(qǐng)求的測(cè)試一般較為簡(jiǎn)單,只需設(shè)置好相關(guān)的請(qǐng)求頭,url寫正確即可。但是在測(cè)試post請(qǐng)求時(shí),請(qǐng)求數(shù)據(jù)格式的設(shè)置往往就稍顯復(fù)雜。尤其是在開發(fā)人員的接口文檔描述不清楚的情況下,會(huì)影響到測(cè)試效率。

故而本文總結(jié)了下post請(qǐng)求常見(jiàn)的四種數(shù)據(jù)格式和他們對(duì)應(yīng)的fiddler、HttpClient模擬請(qǐng)求的構(gòu)造方法。


二、post請(qǐng)求主體詳解

 一個(gè)正常的post請(qǐng)求主要包括請(qǐng)求行,請(qǐng)求頭,請(qǐng)求主體,也就是
 <method><url><version>
 <headers>
 <entity-body> 

對(duì)于get請(qǐng)求來(lái)說(shuō)沒(méi)有請(qǐng)求主體entity-body。對(duì)于post請(qǐng)求而言,不會(huì)對(duì)發(fā)送請(qǐng)求的數(shù)據(jù)格式進(jìn)行限制,理論上你可以發(fā)任意數(shù)據(jù),但是服務(wù)器能不能處理就是另一回事了。服務(wù)器收到數(shù)據(jù)后,如何解析數(shù)據(jù)呢?它會(huì)以請(qǐng)求頭中的Content-Type設(shè)置的內(nèi)容來(lái)進(jìn)行數(shù)據(jù)解析。確定好Content-Type的格式之后,請(qǐng)求主體的數(shù)據(jù)格式也就確定下來(lái)了。Content-Type的格式有四種:分別是application/x-www-form-urlencoded(這也是默認(rèn)格式)、application/json、text/xml以及multipart/form-data格式。
這些不同的post請(qǐng)求數(shù)據(jù)格式要通過(guò)HttpEntity來(lái)構(gòu)造,有必要簡(jiǎn)單理一下HttpClient的HttpEntity對(duì)象,因?yàn)樗械膒ost請(qǐng)求數(shù)據(jù)均需要置于HttpEntity實(shí)體中進(jìn)行發(fā)送。HttpEntity是一個(gè)接口,實(shí)現(xiàn)這個(gè)接口的具體類有很多,比較常用的是StringEntity、UrlEncodedFormEntity(繼承自StringEntity)、MultipartEntity。他們將在發(fā)送不同格式的post請(qǐng)求時(shí)被用到。接下來(lái)就詳細(xì)地介紹每一種數(shù)據(jù)格式對(duì)應(yīng)的fiddler請(qǐng)求模擬和httpClient請(qǐng)求模擬(java實(shí)現(xiàn))的實(shí)現(xiàn)情況。


三、四種Post請(qǐng)求數(shù)據(jù)格式和fiddler和HttpClient模擬請(qǐng)求構(gòu)造

(一)application/x-www-form-urlencoded數(shù)據(jù)格式

W3C官網(wǎng)上明確對(duì)這種數(shù)據(jù)格式進(jìn)行了定義:
This is the default content type. Forms submitted with this content type must be encoded as follows:
Control names and values are escaped. Space characters are replaced by '+', and then reserved characters are escaped as described in [RFC1738], section 2.2: Non-alphanumeric characters are replaced by '%HH', a percent sign and two hexadecimal digits representing the ASCII code of the character. Line breaks are represented as "CR LF" pairs (i.e., '%0D%0A').The control names/values are listed in the order they appear in the document. The name is separated from the value by '=' and name/value pairs are separated from each other by '&'.

這是post請(qǐng)求最常見(jiàn)也是默認(rèn)的數(shù)據(jù)提交格式。它要求數(shù)據(jù)名稱(name)和數(shù)據(jù)值(value)之間以等號(hào)相連,與另一組name/value值之間用&相連。例如:parameter1=12345&parameter2=23456。將請(qǐng)求的內(nèi)容進(jìn)行格式化了,其實(shí)這個(gè)方法同時(shí)簡(jiǎn)化的客戶端發(fā)送,也簡(jiǎn)化了服務(wù)器端獲取,服務(wù)器通過(guò)getParameters(String name)即可獲取到傳送來(lái)的信息。
我們看下如何分別用fiddler和HttpClient的話模擬post請(qǐng)求。
(1)如果用fiddler模擬請(qǐng)求的話,請(qǐng)求頭和請(qǐng)求主體的內(nèi)容可以這樣構(gòu)造:


模擬請(qǐng)求之后,從返回結(jié)果可以查看到我們的請(qǐng)求數(shù)據(jù):


(2)如果用HttpClient模擬post請(qǐng)求的話,請(qǐng)求可以這樣構(gòu)造:

DefaultHttpClient client = new DefaultHttpClient();
List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();     //定義鍵值對(duì)列表,用于存放向url發(fā)送post請(qǐng)求的數(shù)據(jù)。        
params.add(new BasicNameValuePair("parameter1", "12345"));        
params.add(new BasicNameValuePair("parameter2", "23456"));               //向params設(shè)置數(shù)據(jù)        
HttpPost post = new HttpPost("http://example.com");                      //定義HttpPost對(duì)象并初始化它    
HttpEntity reqEntity = new UrlEncodedFormEntity(params);                 //用UrlEncodedFormEntity對(duì)象包裝請(qǐng)求體數(shù)據(jù)                                                   
post.setEntity(reqEntity);                                               //設(shè)置post請(qǐng)求實(shí)體        
HttpResponse response = client.execute(post);                            //發(fā)送http請(qǐng)求        
System.out.println("the request body is:"+EntityUtils.toString(reqEntity));          //打印出請(qǐng)求實(shí)體        
System.out.println(response.getStatusLine().getStatusCode());                         //打印http請(qǐng)求返回碼

**(二)application/json數(shù)據(jù)格式 **
application/json格式的請(qǐng)求頭是指用來(lái)告訴服務(wù)端post過(guò)去的消息主體是序列化后的 JSON 字符串。
(1)如果用fiddler模擬請(qǐng)求的話,請(qǐng)求頭和請(qǐng)求主體的內(nèi)容可以這樣構(gòu)造:


模擬請(qǐng)求之后,從返回結(jié)果可以看到我們的請(qǐng)求數(shù)據(jù):



(2)如果用HttpClient模擬post請(qǐng)求的話,請(qǐng)求可以這樣構(gòu)造:

 HttpClient client = new DefaultHttpClient();   
 JSONObject js = new JSONObject();                                  //定義一個(gè)JSON數(shù)據(jù)格式對(duì)象,用其保存請(qǐng)求主體數(shù)據(jù)。
 js.element("parameter1", "12345");                                 //為JSON對(duì)象的各個(gè)key值賦值
 js.element("parameter2","23456");
 String postRequest = js.toString();
 HttpPost post = new HttpPost("http://example.com");                 //定義HttpPost對(duì)象并初始化它    
 StringEntity reqEntity = new StringEntity(js.toString());           //用StringEntity對(duì)象包裝請(qǐng)求體數(shù)據(jù) 
 reqEntity.setContentType("application/json");                       //設(shè)置請(qǐng)求頭數(shù)據(jù)傳輸格式 
 post.setEntity(reqEntity);                                          //設(shè)置post請(qǐng)求實(shí)體 
 HttpResponse response = client.execute(post);                       //發(fā)送http請(qǐng)求
 System.out.println("the request body is:"+EntityUtils.toString(reqEntity));            //打印出請(qǐng)求實(shí)體
 System.out.println(response.getStatusLine().getStatusCode());                          //打印http請(qǐng)求返回碼

這里我們可以發(fā)現(xiàn)HttpClient模擬post請(qǐng)求時(shí),請(qǐng)求頭格式為application/x-www-form-urlencoded與application/json的主要差別在于請(qǐng)求主體的構(gòu)造格式(前者是鍵值對(duì),后者是JSON串)以及包裝請(qǐng)求體數(shù)據(jù)用的方法不同(前者是UrlEncodedFormEntity,后者是StringEntity)。
** (三)text/xml數(shù)據(jù)格式 **
(1)如果用fiddler模擬請(qǐng)求的話,請(qǐng)求頭和請(qǐng)求主體的內(nèi)容可以這樣構(gòu)造:


模擬請(qǐng)求之后,從返回結(jié)果可以看到我們的請(qǐng)求數(shù)據(jù):


(2)如果用HttpClient模擬post請(qǐng)求的話,請(qǐng)求可以這樣構(gòu)造:

Document doc = DocumentHelper.createDocument();                           //創(chuàng)建document對(duì)象
Element book = doc.addElement("book");                                    //構(gòu)建document對(duì)象各個(gè)節(jié)點(diǎn)
book.addElement("title").addText("羋月傳");
book.addElement("author").addText("蔣勝男");
String body = book.asXML();                                               //Document對(duì)象轉(zhuǎn)成string類型
StringEntity reqEntity = new StringEntity(body);                          //用StringEntity對(duì)象包裝請(qǐng)求體數(shù)據(jù)
reqEntity.setContentType("text/xml");                                     //設(shè)置請(qǐng)求頭數(shù)據(jù)傳輸格式
reqEntity.setContentEncoding("utf-8");                                    //設(shè)置請(qǐng)求頭數(shù)據(jù)編碼格式
HttpPost post = new HttpPost("http://example.com");                       //定義HttpPost對(duì)象并初始化它   
post.setEntity(reqEntity);                                                //設(shè)置post請(qǐng)求實(shí)體
HttpResponse response = client.execute(post);                             //發(fā)送http請(qǐng)求
System.out.println("the request body is:"+EntityUtils.toString(reqEntity));   //打印出請(qǐng)求實(shí)體
System.out.println(response.getStatusLine().getStatusCode());                 //打印http請(qǐng)求返回碼

(四)multipart/form-data數(shù)據(jù)格式
除了傳統(tǒng)的application/x-www-form-urlencoded表單,我們另一個(gè)經(jīng)常用到的是上傳文件用的表單,這種表單的類型為multipart/form-data。在HttpClient程序擴(kuò)展包(HttpMime)中專門有一個(gè)類與之對(duì)應(yīng),那就是MultipartEntity類。此類同樣實(shí)現(xiàn)了HttpEntity接口。
(1)如果用fiddler模擬請(qǐng)求的話,請(qǐng)求頭和請(qǐng)求主體的內(nèi)容可以這樣構(gòu)造:
第一步,先設(shè)置好請(qǐng)求頭格式,然后點(diǎn)擊upload file...


第二步,上傳你的文件,這里我上傳一個(gè)png的圖片


這是fiddler根據(jù)我們上傳的文件自動(dòng)調(diào)整生成的請(qǐng)求,在請(qǐng)求頭中看到,我們需要選擇一段數(shù)據(jù)作為“分割邊界”(boundary屬性),這個(gè)“邊界數(shù)據(jù)”不能在內(nèi)容其他地方出現(xiàn),一般來(lái)說(shuō)使用一段從概率上說(shuō)“幾乎不可能”的數(shù)據(jù)即可。每次post瀏覽器都會(huì)生成一個(gè)隨機(jī)的30-40位長(zhǎng)度的隨機(jī)字符串,瀏覽器一般不會(huì)遍歷這次post的所有數(shù)據(jù)找到一個(gè)不可能出現(xiàn)在數(shù)據(jù)中的字符串,一般都是隨機(jī)生成。選擇了這個(gè)邊界之后,瀏覽器便把它放在Content-Type 里面?zhèn)鬟f給服務(wù)器,服務(wù)器根據(jù)此邊界解析數(shù)據(jù)。下面的數(shù)據(jù)便根據(jù)boundary劃分段,每一段便是一項(xiàng)數(shù)據(jù)。(每個(gè)field被分成小部分,而且包含一個(gè)value是"form-data"的"Content-Disposition"的頭部;一個(gè)"name"屬性對(duì)應(yīng)field的ID等等,文件的話包括一個(gè)filename)
模擬請(qǐng)求之后,從返回結(jié)果可以看到我們的請(qǐng)求數(shù)據(jù):

(2)如果用HttpClient模擬post請(qǐng)求的話,請(qǐng)求可以這樣構(gòu)造:

HttpPost post = new HttpPost("http://example.com");           //定義HttpPost對(duì)象并初始化它
MultipartEntity mutiEntity = new MultipartEntity();           //定義MultipartEntity對(duì)象
File file = new File("C:\Users\hzsuixiang\Desktop\image_20151117151539.png");
mutiEntity.addPart("desc",new StringBody("網(wǎng)易云閱讀", Charset.forName("utf-8")));     //設(shè)置multiEntity對(duì)象的主體數(shù)據(jù)
mutiEntity.addPart("pic", newFileBody(file));post.setEntity(mutiEntity);             //設(shè)置post請(qǐng)求主體
HttpResponse  httpResponse = client.execute(post);                                   //執(zhí)行post請(qǐng)求
HttpEntity httpEntity =  httpResponse.getEntity();                                   //獲得響應(yīng)返回實(shí)體

綜上,就是接口測(cè)試中fiddler與HttpClient模擬post接口四種請(qǐng)求數(shù)據(jù)的構(gòu)造方法,總結(jié)起來(lái)有利于在以后的接口測(cè)試工組過(guò)程中可以及時(shí)查閱。另外,為了盡可能簡(jiǎn)化核心代碼,列出的這些代碼中并沒(méi)有寫出需要的jar包,大家使用的時(shí)候需要自行添加。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容