HttpClient入門(1) 發送請求,處理響應及響應重複讀取

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

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)

HttpEntity.getContent()方式
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);
}
複製代碼
CommonUtils
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();
    }
}
複製代碼
HttpEntity.writeTo方式
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);
}
複製代碼
CommonUtils
public void closeOutputStream(ByteArrayOutputStream outstream) {
    try {
        if (outstream != null) {
	    outstream.close();
	}
    } catch (Exception e) {
        e.printStackTrace();
    }
}
複製代碼

爲了確保資源的正確釋放,採用上述兩種方式讀取正文時,都需對流進行關閉。除此以外,HttpClient還提供了EntityUtils工具類,方便對正文的讀取操做,不過官方文檔中建議,只有當響應實體來自受信任的HTTP服務器,而且已知其長度有限,才能夠採用這種方法。

EntityUtils.toString方式
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方法進行關閉。

經過BufferedHttpEntity實現響應屢次讀取

對於流類型的HttpEntity而言,是不可重複讀取的,若想屢次讀取,則須要在某個地方將HttpEntity緩存起來,最簡單的方式,能夠使用HttpClient提供的BufferedHttpEntity類來實現。

HttpEntity.getContent()+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 "";
    }
}
複製代碼
HttpEntity.writeTo+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(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 "";
    }
}
複製代碼
EntityUtils.toString+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(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請求的發送和響應處理。

相關文章
相關標籤/搜索