httpclient 设置超时时间_面试官:技术选型,HttpClient还是OkHttp?
你知道的越多,不知道的就越多,業余的像一棵小草!
你來,我們一起精進!你不來,我和你的競爭對手一起精進!
編輯:業余草
來源:juejin.im/post/6844904040644476941
推薦:https://www.xttblog.com/?p=5097
寫在前面
為什么會寫這篇文章,起因于和朋友的聊天
這又觸及到我的知識盲區了,首先來一波面向百度學習,直接根據關鍵字 httpclient 和 okhttp 的區別、性能比較進行搜索,沒有找到想要的答案,于是就去 overstackflow 上看看是不是有人問過這個問題,果然不會讓你失望的
所以從使用、性能、超時配置方面進行比較
使用
HttpClient 和 OkHttp 一般用于調用其它服務,一般服務暴露出來的接口都為 http,http 常用請求類型就為 GET、PUT、POST 和 DELETE,因此主要介紹這些請求類型的調用
HttpClient 使用介紹
使用 HttpClient 發送請求主要分為一下幾步驟:
- 創建 CloseableHttpClient 對象或 CloseableHttpAsyncClient 對象,前者同步,后者為異步
- 創建 Http 請求對象
- 調用 execute 方法執行請求,如果是異步請求在執行之前需調用 start 方法
創建連接:
CloseableHttpClient?httpClient?=?HttpClientBuilder.create().build();該連接為同步連接
GET 請求:
@Testpublic?void?testGet()?throws?IOException?{
????String?api?=?"/api/files/1";
????String?url?=?String.format("%s%s",?BASE\_URL,?api);
????HttpGet?httpGet?=?new?HttpGet(url);
????CloseableHttpResponse?response?=?httpClient.execute(httpGet);
????System.out.println(EntityUtils.toString(response.getEntity()));
}
使用 HttpGet 表示該連接為 GET 請求,HttpClient 調用 execute 方法發送 GET 請求
PUT 請求:
@Testpublic?void?testPut()?throws?IOException?{
????String?api?=?"/api/user";
????String?url?=?String.format("%s%s",?BASE\_URL,?api);
????HttpPut?httpPut?=?new?HttpPut(url);
????UserVO?userVO?=?UserVO.builder().name("h2t").id(16L).build();
????httpPut.setHeader("Content-Type",?"application/json;charset=utf8");
????httpPut.setEntity(new?StringEntity(JSONObject.toJSONString(userVO),?"UTF-8"));
????CloseableHttpResponse?response?=?httpClient.execute(httpPut);
????System.out.println(EntityUtils.toString(response.getEntity()));
}
POST 請求:
- 添加對象
public?void?testPost()?throws?IOException?{
?String?api?=?"/api/user";
?String?url?=?String.format("%s%s",?BASE\_URL,?api);
?HttpPost?httpPost?=?new?HttpPost(url);
?UserVO?userVO?=?UserVO.builder().name("h2t2").build();
?httpPost.setHeader("Content-Type",?"application/json;charset=utf8");
?httpPost.setEntity(new?StringEntity(JSONObject.toJSONString(userVO),?"UTF-8"));
?CloseableHttpResponse?response?=?httpClient.execute(httpPost);
?System.out.println(EntityUtils.toString(response.getEntity()));
}
該請求是一個創建對象的請求,需要傳入一個 json 字符串
- 上傳文件
public?void?testUpload1()?throws?IOException?{
?String?api?=?"/api/files/1";
?String?url?=?String.format("%s%s",?BASE\_URL,?api);
?HttpPost?httpPost?=?new?HttpPost(url);
?File?file?=?new?File("C:/Users/hetiantian/Desktop/學習/docker\_practice.pdf");
?FileBody?fileBody?=?new?FileBody(file);
?MultipartEntityBuilder?builder?=?MultipartEntityBuilder.create();
?builder.setMode(HttpMultipartMode.BROWSER\_COMPATIBLE);
?builder.addPart("file",?fileBody);??//addPart上傳文件
?HttpEntity?entity?=?builder.build();
?httpPost.setEntity(entity);
?CloseableHttpResponse?response?=?httpClient.execute(httpPost);
?System.out.println(EntityUtils.toString(response.getEntity()));
}
通過 addPart 上傳文件
DELETE 請求:
@Testpublic?void?testDelete()?throws?IOException?{
????String?api?=?"/api/user/12";
????String?url?=?String.format("%s%s",?BASE\_URL,?api);
????HttpDelete?httpDelete?=?new?HttpDelete(url);
????CloseableHttpResponse?response?=?httpClient.execute(httpDelete);
????System.out.println(EntityUtils.toString(response.getEntity()));
}
請求的取消:
@Testpublic?void?testCancel()?throws?IOException?{
????String?api?=?"/api/files/1";
????String?url?=?String.format("%s%s",?BASE\_URL,?api);
????HttpGet?httpGet?=?new?HttpGet(url);
????httpGet.setConfig(requestConfig);??//設置超時時間
????//測試連接的取消
????long?begin?=?System.currentTimeMillis();
????CloseableHttpResponse?response?=?httpClient.execute(httpGet);
????while?(true)?{
????????if?(System.currentTimeMillis()?-?begin?>?1000)?{
??????????httpGet.abort();
??????????System.out.println("task?canceled");
??????????break;
??????}
????}
????System.out.println(EntityUtils.toString(response.getEntity()));
}
調用 abort 方法取消請求 執行結果:
task?canceledcost?8098?msc
Disconnected?from?the?target?VM,?address:?'127.0.0.1:60549',?transport:?'socket'
java.net.SocketException:?socket?closed...【省略】
OkHttp 使用
使用 OkHttp 發送請求主要分為一下幾步驟:
- 創建 OkHttpClient 對象
- 創建 Request 對象
- 將 Request 對象封裝為 Call
- 通過 Call 來執行同步或異步請求,調用 execute 方法同步執行,調用 enqueue 方法異步執行
創建連接:
private?OkHttpClient?client?=?new?OkHttpClient();GET 請求:
@Testpublic?void?testGet()?throws?IOException?{
????String?api?=?"/api/files/1";
????String?url?=?String.format("%s%s",?BASE\_URL,?api);
????Request?request?=?new?Request.Builder()
????????????.url(url)
????????????.get()
????????????.build();
????final?Call?call?=?client.newCall(request);
????Response?response?=?call.execute();
????System.out.println(response.body().string());
}
PUT 請求:
@Testpublic?void?testPut()?throws?IOException?{
????String?api?=?"/api/user";
????String?url?=?String.format("%s%s",?BASE\_URL,?api);
????//請求參數
????UserVO?userVO?=?UserVO.builder().name("h2t").id(11L).build();
????RequestBody?requestBody?=?RequestBody.create(MediaType.parse("application/json;?charset=utf-8"),
????JSONObject.toJSONString(userVO));
????Request?request?=?new?Request.Builder()
????????????.url(url)
????????????.put(requestBody)
????????????.build();
????final?Call?call?=?client.newCall(request);
????Response?response?=?call.execute();
????System.out.println(response.body().string());
}
POST 請求:
- 添加對象
public?void?testPost()?throws?IOException?{
?String?api?=?"/api/user";
?String?url?=?String.format("%s%s",?BASE\_URL,?api);
?//請求參數
?JSONObject?json?=?new?JSONObject();
?json.put("name",?"hetiantian");
?RequestBody?requestBody?=?RequestBody.create(MediaType.parse("application/json;?charset=utf-8"),?????String.valueOf(json));
?Request?request?=?new?Request.Builder()
???.url(url)
???.post(requestBody)?//post請求
?????.build();
?final?Call?call?=?client.newCall(request);
?Response?response?=?call.execute();
?System.out.println(response.body().string());
}
- 上傳文件
public?void?testUpload()?throws?IOException?{
?String?api?=?"/api/files/1";
?String?url?=?String.format("%s%s",?BASE\_URL,?api);
?RequestBody?requestBody?=?new?MultipartBody.Builder()
???.setType(MultipartBody.FORM)
???.addFormDataPart("file",?"docker\_practice.pdf",
?????RequestBody.create(MediaType.parse("multipart/form-data"),
???????new?File("C:/Users/hetiantian/Desktop/學習/docker\_practice.pdf")))
???.build();
?Request?request?=?new?Request.Builder()
???.url(url)
???.post(requestBody)??//默認為GET請求,可以不寫
???.build();
?final?Call?call?=?client.newCall(request);
?Response?response?=?call.execute();
?System.out.println(response.body().string());
}
通過 addFormDataPart 方法模擬表單方式上傳文件
DELETE 請求:
@Testpublic?void?testDelete()?throws?IOException?{
??String?url?=?String.format("%s%s",?BASE\_URL,?api);
??//請求參數
??Request?request?=?new?Request.Builder()
??????????.url(url)
??????????.delete()
??????????.build();
??final?Call?call?=?client.newCall(request);
??Response?response?=?call.execute();
??System.out.println(response.body().string());
}
請求的取消:
@Testpublic?void?testCancelSysnc()?throws?IOException?{
????String?api?=?"/api/files/1";
????String?url?=?String.format("%s%s",?BASE\_URL,?api);
????Request?request?=?new?Request.Builder()
????????????.url(url)
????????????.get()
????????????.build();
????final?Call?call?=?client.newCall(request);
????Response?response?=?call.execute();
????long?start?=?System.currentTimeMillis();
????//測試連接的取消
????while?(true)?{
?????????//1分鐘獲取不到結果就取消請求
????????if?(System.currentTimeMillis()?-?start?>?1000)?{
????????????call.cancel();
????????????System.out.println("task?canceled");
????????????break;
????????}
????}
????System.out.println(response.body().string());
}
調用 cancel 方法進行取消 測試結果:
task?canceledcost?9110?msc
java.net.SocketException:?socket?closed...【省略】
小結
- OkHttp 使用 build 模式創建對象來的更簡潔一些,并且使用. post/.delete/.put/.get 方法表示請求類型,不需要像 HttpClient 創建 HttpGet、HttpPost 等這些方法來創建請求類型
- 依賴包上,如果 HttpClient 需要發送異步請求、實現文件上傳,需要額外的引入異步請求依賴
?<dependency>
??<groupId>org.apache.httpcomponentsgroupId>
??<artifactId>httpmimeartifactId>
??<version>4.5.3version>
?dependency>
?
?<dependency>
??<groupId>org.apache.httpcomponentsgroupId>
??<artifactId>httpasyncclientartifactId>
??<version>4.5.3version>
?dependency>
- 請求的取消,HttpClient 使用 abort 方法,OkHttp 使用 cancel 方法,都挺簡單的,如果使用的是異步 client,則在拋出異常時調用取消請求的方法即可
超時設置
HttpClient 超時設置:在 HttpClient4.3 + 版本以上,超時設置通過 RequestConfig 進行設置
private?CloseableHttpClient?httpClient?=?HttpClientBuilder.create().build();private?RequestConfig?requestConfig?=??RequestConfig.custom()
????????.setSocketTimeout(60?\*?1000)
????????.setConnectTimeout(60?\*?1000).build();
String?api?=?"/api/files/1";
String?url?=?String.format("%s%s",?BASE\_URL,?api);
HttpGet?httpGet?=?new?HttpGet(url);
httpGet.setConfig(requestConfig);??//設置超時時間
超時時間是設置在請求類型 HttpGet 上,而不是 HttpClient 上
OkHttp 超時設置:直接在 OkHttp 上進行設置
private?OkHttpClient?client?=?new?OkHttpClient.Builder()????????.connectTimeout(60,?TimeUnit.SECONDS)//設置連接超時時間
????????.readTimeout(60,?TimeUnit.SECONDS)//設置讀取超時時間
????????.build();
小結:如果 client 是單例模式,HttpClient 在設置超時方面來的更靈活,針對不同請求類型設置不同的超時時間,OkHttp 一旦設置了超時時間,所有請求類型的超時時間也就確定
HttpClient 和 OkHttp 性能比較
測試環境:
- CPU 六核
- 內存 8G
- windows10
每種測試用例都測試五次,排除偶然性
client 連接為單例:
imgclient 連接不為單例:
img單例模式下,HttpClient 的響應速度要更快一些,單位為毫秒,性能差異相差不大 非單例模式下,OkHttp 的性能更好,HttpClient 創建連接比較耗時,因為多數情況下這些資源都會寫成單例模式,因此圖一的測試結果更具有參考價值
總結
OkHttp 和 HttpClient 在性能和使用上不分伯仲,根據實際業務選擇即可
總結
以上是生活随笔為你收集整理的httpclient 设置超时时间_面试官:技术选型,HttpClient还是OkHttp?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 远程登录另一个mysql 数据库_Ubu
- 下一篇: 网络打印机查找不到_打印机驱动的安装教程