httpclient封装获取响应实体_Httpclient 接口自动化
好久木寫啦!!!好久木寫啦!!!
心血來潮分享點小白的東西!!!
廢話少說直接干貨!!!
本文核心是將如何從數據驅動開始,以報告結尾的形式來實現“很多剛入行朋友們”所需要的接口自動化
類型:驅動:excel
核心jar:httpclient
編譯:maven(跟本文所講有點沾不著邊)
自動化框架 :testng(這個支持并發所以實現了并發的方法)
報告:ztest(有在之前tester老大哥的開源報告上實現了修改)
總結關鍵字:httpclient+maven+testng+ztest+excel
maven pom配置:
org.apache.httpcomponents
httpclient
4.5.5
com.alibaba
fastjson
1.2.47
org.testng
testng
6.14.3
test
其實實現可以很簡單,因為在實現的過程中加入了并發的支持所以實現起來就變成了下面這樣子(寫的很水不喜勿噴)
請求類具體實現方式:
httpclient配置類:這個配置類主要目的分為三類
①如何支持https請求
②如何支持線程池
③自定義請求重試的機制
https是安全的ssl請求,官方給出的要想支持https請求就必須繞過請求證書,至于如何繞過需要實現一個X509TrustManager的接口
private static SSLContext createIgnoreVerifySSL() {
SSLContext sc = null;
try {
sc = SSLContext.getInstance("SSLv3");
} catch (NoSuchAlgorithmException e) {
logger.error("算法異常", e);
}
// 實現一個X509TrustManager接口,用于繞過驗證,不用修改里面的方法
X509TrustManager trustManager = new X509TrustManager() {
public void checkClientTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) throws CertificateException {
}
public void checkServerTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) throws CertificateException {
}
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
};
try {
sc.init(null, new TrustManager[] { trustManager }, null);
} catch (KeyManagementException e) {
logger.error("密鑰管理異常", e);
}
return sc;
}
這樣子下來ssl的配置就有了,然后在httpclient里面實現線程池的方法里面配置這個就好了
這樣子就得到了線程池的對象,然后再給線程池一頓配置,具體代碼有注釋解釋
第三個請求自定義重試機制(也可使用默認的重試機制,不實現這個方法,去掉這個配置就好了setRetryHandler(myRetryHandler)),我偏不信邪我就喜歡重寫一個
這樣子下來我需要的一些配置就有了
public synchronized static CloseableHttpClient createClient() {
SSLContext sslcontext = createIgnoreVerifySSL();
// 驗證http,https請求,使用默認的連接請求,如有自定義需要
// 請查看https://hc.apache.org/httpcomponents-client-4.5.x/tutorial/html/connmgmt.html#d5e449,官方自定義證書驗證文檔
Registry registry = RegistryBuilder. create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", new SSLConnectionSocketFactory(sslcontext)).build();
// 線程池設置
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);// registry
// 最大連接總數
cm.setMaxTotal(MAX_CONN);
// 默認路由最大連接數
cm.setDefaultMaxPerRoute(Max_PRE_ROUTE);
// 主機端口最大連接數
HttpHost localhost = new HttpHost("music.migu.cn", 8000);
cm.setMaxPerRoute(new HttpRoute(localhost), MAX_ROUTE);
// http請求重試處理機制,重寫方法
HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() {
public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
if (executionCount >= 10) {
logger.error("重試次數超過5", new Throwable("重試次數超過5"));
return false;
}
if (exception instanceof InterruptedIOException) {
logger.error("中斷IO異常", new Throwable("中斷IO異常"));
return false;
}
if (exception instanceof UnknownHostException) {
new Throwable().getMessage();
logger.error("未知主機");
return false;
}
if (exception instanceof ConnectTimeoutException) {
logger.error("連接超時", new Throwable("連接超時"));
return false;
}
if (exception instanceof SSLException) {
logger.error("sll握手異常", new Throwable("sll握手異常"));
return false;
}
HttpClientContext clientContext = HttpClientContext.adapt(context);
HttpRequest request = clientContext.getRequest();
boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
if (idempotent) {
logger.error("帶有請求的實體自動重試", new Throwable());
return true;
}
return false;
}
};
// 創建自定義將請求重試機制添加進去;客戶端分createDefault() 與 custom()
CloseableHttpClient httpclient = HttpClients.custom().setKeepAliveStrategy(getkeepAliveStrat())
.setConnectionManager(cm).setRetryHandler(myRetryHandler).build();
return httpclient;
}
配置有了之后怎么辦呢,那當然是實現請求啊
這里需要給大家科普一下頭,頭分為請求頭跟響應頭(網上大佬們寫的我覺得還不錯),因為請求頭能自定義還是說一下比較好
請求方的http報頭結構:通用報頭|請求報頭|實體報頭
響應方的http報頭結構:通用報頭|響應報頭|實體報頭
Accept代表發送端(客戶端)希望接受的數據類型。
比如:Accept:text/xml;?/是所有類型都接受
代表客戶端希望接受的數據類型是xml類型
Content-Type代表發送端(客戶端|服務器)發送的實體數據的數據類型。
比如:Content-Type:text/html;
代表發送端發送的數據格式是html。
解釋完了然后開始實現get,post請求;實現請求之前需要在寫一個setCookie的方法
寫完了cookie之后就就可以當個人了
public BasicHeader setCookie(String head) {
BasicHeader cookie = new BasicHeader("Cookie", head);
return cookie;
}
接下來是get方法
get方法里面有兩點必須要說明的 一個是response響應頭信息,一個是response響應實體
response響應頭:getReponsemes(response) 這個類實現了解析響應頭里面的各種信息里面包含了兩種方法
response響應實體:getResponseEntity(getEntity)響應實體httpclien官網給了一個流解析的api,但是這個api在某些時候會有bug所以這個流的解析基礎上面又加入了一個解析判斷,都有注釋有注釋你們看的懂的
這兩個方法我就不細說了,后面我會放上git鏈接看官們可以自取
public List get(String url, String head) throws Exception {
List resList = new ArrayList();
CloseableHttpClient httpclient = HttpClientMain.createClient();// 創建客戶端
CloseableHttpResponse response = null;// 創建響應
String res = null;// 請求結果
String statu = null;
int status;// 狀態碼
HttpEntity getEntity = null;
HttpGet get = null;
HttpClientContext context = HttpClientContext.create();
BasicHeader cookie = setCookie(head);
get = new HttpGet(url);
// get.setRequestProperty("Content-Type",
// "application/x-www-form-urlencoded;charset=utf-8");
// get.setRequestProperty("accept", "*/*");
// get.setHeader("HTTP_CLIENT_IP", "192.168.10.100");
get.addHeader("user-agent",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36");
get.addHeader("Content-Type", CONTENT_TYPE_FORM_URLENCODED);
get.addHeader("accept", "*/*");
get.setHeader(cookie);
if (httpclient != null) {
response = httpclient.execute(get, context);
if (response != null) {
status = response.getStatusLine().getStatusCode();
getEntity = response.getEntity();
statu = response.getStatusLine().toString();
res = getResponseEntity(getEntity);
resList.add(getReponsemes(response).toString());
resList.add(statu);
resList.add(res);
if (status != 200) {
throw new Exception(res);
}
}
}
closeAll(httpclient, response);
return resList;
}
post方法:post方法多了一個請求參數至于怎么
public List post(String url, Map params, String head) throws Exception {
List resList = new ArrayList();
CloseableHttpClient httpclient = null;// 創建客戶端
CloseableHttpResponse response = null;// 創建響應
HttpEntity postEntity = null;// 請求結果
HttpPost httpPost = null;// 請求方法
int statusCode;// 狀態碼
String res = null;
String statu = null;
BasicHeader cookie = setCookie(head);
httpclient = createClient();
HttpClientContext context = HttpClientContext.create();
httpPost = new HttpPost(url);
httpPost = setPostParams(httpPost, params, context, httpclient);
httpPost.addHeader("user-agent",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36");
httpPost.addHeader("Content-Type", CONTENT_TYPE_FORM_URLENCODED);
httpPost.addHeader("accept", "*/*");
httpPost.setHeader(cookie);
response = httpclient.execute(httpPost, HttpClientContext.create());
statusCode = response.getStatusLine().getStatusCode();
// getReponsemes(response);
if (response != null) {
statusCode = response.getStatusLine().getStatusCode();
postEntity = response.getEntity();
statu = response.getStatusLine().toString();
res = getResponseEntity(postEntity);
resList.add(getReponsemes(response).toString());
resList.add(statu);
resList.add(res);
if (statusCode != 200) {
throw new Exception(res);
}
}
return resList;
}
好了到這里基本的主要方法都有了,然后利用testng去實現這些請求了
如果你深入了解testng這些看起來就很簡單了
一個數據驅動方法,一個test方法,一個ztest的監聽就完事了
@Listeners({ ZTestReport.class })
public class TestTemplate extends TestBase {
private String excelPath = prop1.getProperty("ExcelPath");
private String sheetName = "api";
private List re = null;
@Test(dataProvider = "data", threadPoolSize = 1, timeOut = 0, invocationCount = 1)
public synchronized void getData(String num, String nicName, String httpType, String reMethond, String host,
String path, String head, String paramType, String param, String verisy) throws Exception {
// 獲取當前線程id System.out.println(Thread.currentThread().getId());
SendRequest sr = new SendRequest(num, nicName, httpType, reMethond, host, path, head, paramType, param, verisy);
re = sr.request();
for(String entry:re){
Reporter.log(entry);
}
}
/**
* 數據驅動
*/
@DataProvider(name = "data", parallel = true)
public Object[][] dataProvider() throws IOException, Exception {
return ExcelDataParam.readExcelDataParam(excelPath, sheetName);
}
然后只用到了test標簽至于為什么完全是為了并發,至于是不是并發效果各位看官們可以打印時間到毫秒來看看,也可以打印線程id,至于支持多少并發完全取決于你的機器支持多少線程這里不多講,干活基本就這么多了
少了一個SendRequest
這個類主要是繼承了配置文件(比如你想配置開發,測試,生產的主機可以卸載配置文件里面)
這個類主要就是根據驅動里面的參數來判斷怎么去執行,各個參數為空該怎么執行,參數類型不同該怎么執行沒有技術含量的
public class SendRequest extends TestBase {
private String num;// 編號
private String nicName;// 用例名稱
private String httpType;// 請求協議類型
private String reMethond;// 請求方法
private String host;// 主機
private String path;// 路徑
private String head;// 請求頭
private String paramType;// 參數類型 json param
private String param;// 請求參數
private String verisy;// 驗證點
public SendRequest(String num, String nicName, String httpType, String reMethond, String host, String path,
String head, String paramType, String param, String verisy) {
this.num = num;
this.nicName = nicName;
this.httpType = httpType;
this.reMethond = reMethond;
this.host = host;
this.path = path;
this.head = head;
this.paramType = paramType;
this.param = param;
this.verisy = verisy;
}
/**
* 根據驅動類型來選擇調用方法與參數類型接口調用類
*/
public List request() throws Exception {
List re = null;
if (path == null) {
path = "/";
}
if (host == null) {
host = prop1.getProperty("Host");
}
HttpClientMain req = new HttpClientMain();
if (reMethond.equalsIgnoreCase("get")) {
re = req.get(httpType + "://" + host + path, head);
} else {
// 如果是json參數先把字符串轉json,在把json轉map
if (paramType.equalsIgnoreCase("json")) {
JSONObject json = JSONObject.parseObject(param);
re = req.post(httpType + "://" + host + path, JsonToMap.jsonToMap(json), head);
} else {
re = req.post(httpType + "://" + host + path, ParToMap.strToMap(param), head);
}
}
return re;
}
}
至于報告是怎么實現的:https://testerhome.com/topics/10802 請看一下這位大佬的,對了大佬的報告沒有驗證點,所以我加上了后面git上面的rereport就是加了驗證點的報告,大佬好一手jqury 害的我百度半天才加上
有疑問的跟我一樣的小白們留言就好看到就會回
如果想罵人的請看這里:我手癢想些,就是手癢啊啊啊啊啊啊
總結
以上是生活随笔為你收集整理的httpclient封装获取响应实体_Httpclient 接口自动化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 01背包算法图解
- 下一篇: 如何使用PDF虚拟打印机打印文件