國內(nèi)新聞最新消息10條20235g網(wǎng)絡(luò)優(yōu)化培訓
一、介紹
HttpClient 是Apache Jakarta Common 下的子項目,可以用來提供高效的、最新的、功能豐富的支持 HTTP 協(xié)議的客戶端編程工具包,并且它支持 HTTP 協(xié)議最新的版本和建議。
我們可以通過這個HttpClient工具,在java代碼中去構(gòu)造和發(fā)送http請求
了解http
http的長短連接
要搞清楚編程語言層面http client的使用,就得先對http協(xié)議有所了解。
你應該知道http的transfer layer(傳輸層)其實是tcp協(xié)議
,而tcp協(xié)議最關(guān)鍵的就是一次連接的建立到釋放需要經(jīng)過三次握手,四次揮手。
那么如果你連續(xù)訪問同一個服務器n次,就得建立n次連接,顯然很耗費時間,用戶使用體驗不好,也沒有必要。
于是從HTTP1.1協(xié)議開始,有了所謂的長連接(persistent connection)
,而且客戶端默認行為就是長連接(需要服務端也打開長連接才能實際生效),有了長連接,那么原來
一次連接=一次請求+一次響應,現(xiàn)在可以一次連接=(一次請求+一次響應)*n,n>=1。
tips:注意連接和請求是兩個不同的概念。
這樣子對于連續(xù)n次請求同一服務器的場景來說,就比原來減少了n-1次連接,也就是減少了(3次握手+4次揮手)*(n-1)的時間。
當然,在實際使用中,這里的請求次數(shù)n
是有l(wèi)imitation的,即使你沒有手動設(shè)置,其本身肯定也有一個默認值。
除了請求數(shù)量上有限制外,一般還有時間上的限制,這里的時間限制包括連接的空閑時間
和最大存活時間
(這兩個概念是不同的)。上面我使用了連續(xù)請求這個詞語,連續(xù)是個很抽象的概念,得使用量級去定義它,所以timeout就表明了兩次連接時間間隔得在timeout內(nèi)才算作連續(xù)。超過這個時間長連接會被釋放掉。
一般在請求頭或者響應頭通過這個字段定義:
Keep-Alive: timeout=5, max=1000
這表明長連接的空閑時間為5s,時間單位是秒。
tips:在軟件設(shè)計中,邊界思想是很重要的。
那客戶端這一頭是如何控制開啟長短連接的呢?
請求頭的這個字段:Connection。
Connection: close->禁止長連接
Connection: keep-alive->使用長連接
官網(wǎng)原話是:
HTTP/1.1 defines the “close” connection option for the sender to signal that the
connection will be closed after completion of the response.
由于默認行為是長連接了(相當于默認值keep-alive),所以如果不想要長連接,那么需要顯示指明這個請求頭
字段的值為close。
有時候要小心一點的就是服務端沒有打開長連接的支持(默認打開),雖然一般情況下不會有人這么做,但是原理還是要知道的。
還有一點就是連接的關(guān)閉可以分為client主動關(guān)閉還是server端關(guān)閉,并不一定總是server端關(guān)閉的連接。
連接池概念
在apache http client中,連接是由連接管理對象來管理,有兩種類型。
一種是Simple connection manager(對應的是asicHttpClientConnectionManager.java),
一種就是Pooling connection manager(對應的是PoolingHttpClientConnectionManager.java)。
從名字上看就知道一個是一個http client對應一個connection,一個是一個http client對應一個connection pool,既然是pool,那么connection的數(shù)量就可能是n。
tips:http client和connection是兩個不同的概念。
需要注意的是,如果沒有明確的指定connnection manager,通過HttpClientBuilder.java創(chuàng)建http client的話默認會為你創(chuàng)建的是Pooling connection manager。
根據(jù)實際需要選擇,一般我都偏向于將http client作為單例使用。
了解http 來自:https://zhuanlan.zhihu.com/p/341584129
二、使用
HttpClient的核心API:
- HttpClient:Http客戶端對象類型,使用該類型對象可發(fā)起Http請求。
- HttpClients:可認為是構(gòu)建器,可創(chuàng)建HttpClient對象。
- CloseableHttpClient:實現(xiàn)類,實現(xiàn)了HttpClient接口。
- HttpGet:Get方式請求類型。
- HttpPost:Post方式請求類型。
發(fā)送請求步驟
- 創(chuàng)建httpclient 對象
- 創(chuàng)建 httpclient 請求對象【實例】
- 如果需要發(fā)送GET請求,創(chuàng)建HttpGet對象;如果需要發(fā)送POST請求,創(chuàng)建HttpPost對象。
- 如果需要發(fā)送請求參數(shù),可調(diào)用setEntity(HttpEntity entity)方法來設(shè)置請求參數(shù);
- 調(diào)用httpclient 的execute方法發(fā)送請求
三、代碼案例
采用的是阿里云的sdk-oss(包含了httpclient)
<dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId>
</dependency>
GET
/*** 測試通過httpclient發(fā)送GET方式的請求*/@Testpublic void testGET() throws Exception{//創(chuàng)建httpclient對象CloseableHttpClient httpClient = HttpClients.createDefault();//創(chuàng)建請求對象HttpGet httpGet = new HttpGet("http://localhost:8080/user/shop/status");//發(fā)送請求,接受響應結(jié)果CloseableHttpResponse response = httpClient.execute(httpGet);//獲取服務端返回的狀態(tài)碼int statusCode = response.getStatusLine().getStatusCode();System.out.println("服務端返回的狀態(tài)碼為:" + statusCode);HttpEntity entity = response.getEntity();String body = EntityUtils.toString(entity);System.out.println("服務端返回的數(shù)據(jù)為:" + body);//關(guān)閉資源response.close();httpClient.close();}
POST
/*** 測試通過httpclient發(fā)送POST方式的請求*/@Testpublic void testPOST() throws Exception{// 創(chuàng)建httpclient對象CloseableHttpClient httpClient = HttpClients.createDefault();//創(chuàng)建請求對象HttpPost httpPost = new HttpPost("http://localhost:8080/admin/employee/login");JSONObject jsonObject = new JSONObject();jsonObject.put("username","admin");jsonObject.put("password","123456");StringEntity entity = new StringEntity(jsonObject.toString());//指定請求編碼方式entity.setContentEncoding("utf-8");//數(shù)據(jù)格式entity.setContentType("application/json");httpPost.setEntity(entity);//發(fā)送請求CloseableHttpResponse response = httpClient.execute(httpPost);//解析返回結(jié)果int statusCode = response.getStatusLine().getStatusCode();System.out.println("響應碼為:" + statusCode);HttpEntity entity1 = response.getEntity();String body = EntityUtils.toString(entity1);System.out.println("響應數(shù)據(jù)為:" + body);//關(guān)閉資源response.close();httpClient.close();}