HttpClient是Apache旗下的項目,是一個負責建立和維護HTTP和相關協議的工具集。html
如下分析使用版本爲: httpclient-4.5.3.jar, httpcore-4.4.6.jar, jdk1.8.0_131 全部示例代碼均通過運行測試緩存
httpclient最重要的功能就是發送http請求,下面介紹如何執行一個get請求:bash
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet get = new HttpGet("http://www.jianshu.com/u/8a3115bb299c");
try(CloseableHttpResponse response = httpclient.execute(get)) {
HttpEntity entity = response.getEntity();
System.out.println(EntityUtils.toString(entity, "UTF-8"));
} catch (Exception e) {
e.printStackTrace();
}
複製代碼
httpclient支持Http/1.1規範中定義的全部方法:GET,HEAD,POST,PUT,DELETE,TRACE,OPTIONS,對應的類是:HttpGet,HttpHead,HttpPost,HttpPut,HttpDelete,HttpTrace,HttpOptions。服務器
URI(統一資源標識符),用於標識應用請求的資源,一般由協議版本,主機名,端口(可選),資源路徑,參數名(可選),參數值(可選)組成。 請求時,能夠經過拼接字符串的形式訪問:app
HttpGet get = new HttpGet("http://www.jianshu.com/p/7021031d6e49?utm_medium=index-banner&utm_source=desktop");
複製代碼
httpclient也提供了URIBuilder這個類簡化請求URI的建立和修改。工具
URI uri = new URIBuilder()
.setScheme("http")
.setHost("www.jianshu.com")
.setPath("/p/7021031d6e49")
.setParameter("utm_medium", "index-banner")
.setParameter("utm_source", "desktop")
.build();
HttpGet httpget = new HttpGet(uri);
System.out.println(httpget.getURI());
複製代碼
輸出測試
http://www.jianshu.com/p/7021031d6e49?utm_medium=index-banner&utm_source=desktop
複製代碼
http請求是客戶端發給服務端的一個消息,消息的第一行包括了請求方法,URI以及使用的協議版本。ui
HttpGet get = new HttpGet("http://www.jianshu.com/u/8a3115bb299c");
RequestLine requestLine = get.getRequestLine();
System.out.println(requestLine.getMethod());
System.out.println(requestLine.getUri());
System.out.println(requestLine.getProtocolVersion());
System.out.println(requestLine);
複製代碼
輸出spa
GET
http://www.jianshu.com/u/8a3115bb299c
HTTP/1.1
GET http://www.jianshu.com/u/8a3115bb299c HTTP/1.1
複製代碼
服務端接收並處理請求後,會返回消息給到客戶端,該消息的第一行包括協議版本,狀態碼以及描述文字。code
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet get = new HttpGet("http://www.jianshu.com/u/8a3115bb299c");
try(CloseableHttpResponse response = httpclient.execute(get)) {
System.out.println(response.getStatusLine());
System.out.println(response.getProtocolVersion());
System.out.println(response.getStatusLine().getStatusCode());
System.out.println(response.getStatusLine().getReasonPhrase());
System.out.println(response.getStatusLine().toString());
} catch (Exception e) {
e.printStackTrace();
}
複製代碼
輸出
HTTP/1.1 200 OK
HTTP/1.1
200
OK
HTTP/1.1 200 OK
複製代碼
服務端返回的響應被封裝在HttpEntity,經過HttpEntity能夠獲取請求響應的一些元信息,好比Content-Type,Content-Length以及Content-Encoding,元信息需由服務端提供,不然將是空值。
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet get = new HttpGet("http://www.jianshu.com/u/8a3115bb299c");
try(CloseableHttpResponse response = httpclient.execute(get)) {
HttpEntity entity = response.getEntity();
System.out.println(entity.getContentType());
System.out.println(entity.getContentLength());
System.out.println(entity.getContentEncoding());
} catch (Exception e) {
e.printStackTrace();
}
複製代碼
輸出
Content-Type: text/html; charset=utf-8
-1
null
複製代碼
HttpEntity提供了多種方法來讀取正文,官方文檔推薦使用如下方法進行讀取:HttpEntity.getContent()
與 HttpEntity.writeTo(outputStream)
CloseableHttpClient httpclient = null;
CloseableHttpResponse response = null;
BufferedReader reader = null;
try {
httpclient = HttpClients.createDefault();
HttpGet get = new HttpGet("http://www.jianshu.com/u/8a3115bb299c");
response = httpclient.execute(get);
HttpEntity entity = response.getEntity();
reader = new BufferedReader(new InputStreamReader(entity.getContent(), "UTF-8"));
String str = "";
StringBuilder sb = new StringBuilder();
while ((str = reader.readLine()) != null) {
sb.append(str).append("\n");
}
System.out.println(sb);
} catch (Exception e) {
e.printStackTrace();
} finally {
CommonUtils.closeReader(reader);
CommonUtils.closeResponse(response);
CommonUtils.closeHttpClient(httpclient);
}
複製代碼
public void closeReader(BufferedReader reader) {
try {
if (reader != null) {
reader.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void closeResponse(CloseableHttpResponse response) {
try {
if (response != null) {
response.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void closeHttpClient(CloseableHttpClient httpclient) {
try {
if (httpclient != null) {
httpclient.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
複製代碼
CloseableHttpClient httpclient = null;
CloseableHttpResponse response = null;
ByteArrayOutputStream outstream = new ByteArrayOutputStream();
try {
httpclient = HttpClients.createDefault();
HttpGet get = new HttpGet("http://www.jianshu.com/u/8a3115bb299c");
response = httpclient.execute(get);
HttpEntity entity = response.getEntity();
entity.writeTo(outstream);
System.out.println(outstream.toString("UTF-8"));
} catch (Exception e) {
e.printStackTrace();
} finally {
CommonUtils.closeOutputStream(outstream);
CommonUtils.closeResponse(response);
CommonUtils.closeHttpClient(httpclient);
}
複製代碼
public void closeOutputStream(ByteArrayOutputStream outstream) {
try {
if (outstream != null) {
outstream.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
複製代碼
爲了確保資源的正確釋放,採用上述兩種方式讀取正文時,都需對流進行關閉。除此以外,HttpClient還提供了EntityUtils工具類,方便對正文的讀取操做,不過官方文檔中建議,只有當響應實體來自受信任的HTTP服務器,而且已知其長度有限,才能夠採用這種方法。
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet get = new HttpGet("http://www.jianshu.com/u/8a3115bb299c");
try(CloseableHttpResponse response = httpclient.execute(get)) {
HttpEntity entity = response.getEntity();
System.out.println(EntityUtils.toString(entity, "UTF-8"));
} catch (Exception e) {
e.printStackTrace();
} finally {
CommonUtils.closeHttpClient(httpclient);
}
複製代碼
EntityUtils.toString內部會對HttpEntity中的輸入流進行關閉。 以上三種讀取方式,當CloseableHttpClient的實例再也不使用時,都需調用close方法進行關閉。
對於流類型的HttpEntity而言,是不可重複讀取的,若想屢次讀取,則須要在某個地方將HttpEntity緩存起來,最簡單的方式,能夠使用HttpClient提供的BufferedHttpEntity類來實現。
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet get = new HttpGet("http://www.jianshu.com/u/8a3115bb299c");
try(CloseableHttpResponse response = httpclient.execute(get)) {
HttpEntity entity = response.getEntity();
BufferedHttpEntity bufferedEntity = new BufferedHttpEntity(entity);
System.out.println(getEntityContent(bufferedEntity));
System.out.println(getEntityContent(bufferedEntity));
} catch (Exception e) {
e.printStackTrace();
} finally {
CommonUtils.closeHttpClient(httpclient);
}
複製代碼
public String getEntityContent(HttpEntity entity) {
try(BufferedReader reader = new BufferedReader(new InputStreamReader(entity.getContent(), "UTF-8"))) {
String str = "";
StringBuilder sb = new StringBuilder();
while ((str = reader.readLine()) != null) {
sb.append(str).append("\n");
}
return sb.toString();
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
複製代碼
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet get = new HttpGet("http://www.jianshu.com/u/8a3115bb299c");
try(CloseableHttpResponse response = httpclient.execute(get)) {
HttpEntity entity = response.getEntity();
BufferedHttpEntity bufferedEntity = new BufferedHttpEntity(entity);
System.out.println(getContentByWriteTo(bufferedEntity));
System.out.println(getContentByWriteTo(bufferedEntity));
} catch (Exception e) {
e.printStackTrace();
} finally {
CommonUtils.closeHttpClient(httpclient);
}
複製代碼
public String getContentByWriteTo(HttpEntity entity) {
try(ByteArrayOutputStream outstream = new ByteArrayOutputStream()) {
entity.writeTo(outstream);
return outstream.toString("UTF-8");
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
複製代碼
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet get = new HttpGet("http://www.jianshu.com/u/8a3115bb299c");
try(CloseableHttpResponse response = httpclient.execute(get)) {
HttpEntity entity = response.getEntity();
BufferedHttpEntity bufferedEntity = new BufferedHttpEntity(entity);
System.out.println(EntityUtils.toString(bufferedEntity, "UTF-8"));
System.out.println(EntityUtils.toString(bufferedEntity, "UTF-8"));
} catch (Exception e) {
e.printStackTrace();
} finally {
CommonUtils.closeHttpClient(httpclient);
}
複製代碼
至此,經過HttpClient,簡單實現了http get請求的發送和響應處理。