HttpClient詳細解釋

前言html

HttpClient相對傳統JDK自帶的URLConnection,,增長了易用性和靈活性,它不只使客戶端發生HTTP請求變得容易,並且也方便了開發人員測試接口(基於HTTP協議),既提升了開發的效率,也提升了代碼的健壯性。所以熟練掌握HTTPClient是很重要的必修課,掌握httpclient後,相信對於HTTP協議的瞭解會更加深刻。java

1、簡介apache

httpclient是Apache Jakarta common下的子項目,用來提供高效的、最新的、更能豐富的支持http協議的客戶端編程工具包,而且它支持http協議最新的版本和建議。httpclient已經應用在不少項目中,好比Apache Jakarta上很著名的兩個開源項目cactus和httplunit都使用了httpclient。編程

2、特效服務器

1.基於標準、純淨的Java語言。實現了HTTP1.0和HTTP1.1session

2.以可擴展的面向對象的結構實現了HTTP所有的方法(GET、POST、put、delete、head、options、trace)。多線程

3.支持HTTPS協議。併發

4.經過HTTP代理創建透明的鏈接。socket

5.利用connect方法經過HTTP代理創建隧道的HTTPS鏈接。工具

6.basic,digest,htlmv1,htlmv2,htlm2 session,snpnego/kerberos認證方案。

7.插件式的自定義認證方案。

8.便攜可靠的套接字工廠是它更容易的使用第三方解決方案。

9.鏈接管理器支持多線程應用。支持設置最大鏈接數,同事支持設置每一個主機的最大鏈接數,發現並關閉過時的鏈接。

10.自動處理Set-Cookie中的Cookie。

11.插件式的自定義Cookie策略。

12.request的輸出流能夠避免流中內容直接緩衝到socket服務器。

13.Response的輸入流能夠有效的從socket服務器直接讀取相應內容。

14.在http1.0和http1.1中利用KeepAlive保持持久鏈接。

15.直接獲取服務器發送的response code和 headers。

16.設置鏈接超時的能力。

17.實驗性的支持http1.1 response caching。

18.源代碼基於Apache License 可免費獲取。

3、使用方法

使用HttpClient發送請求、接收響應很簡單,通常須要以下幾步便可。
一、建立httpclient對象。
二、建立請求方法的實例,並制定請求url。若是須要發送get請求,建立httpclient對象;若是須要發送post請求,建立httpPOST對象。
三、若是須要發送請求參數,可調用httpget、httpPost共同的setparams(HetpParams params)方法來添加請求參數;對於HttpPost對象而言,也可調用setEntity(HttpEntity entity)方法來設置請求參數。
四、調用HttpClient對象的execute(HttpUriRequest request)發送請求,該方法返回一個HttpResponse。
五、調用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可獲取服務器的響應頭;調用HttpResponse的getEntity()方法可獲取HttpEntity對象,該對象包裝了服務器的響應內容。程序可經過該對象獲取服務器的響應內容。
六、釋放鏈接。不管執行方法是否成功,都必須釋放鏈接。
4、獲取頁面代碼

package http.HttpClient;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

public class GetCode {
    public static void main(String[] args) throws ClientProtocolException, IOException {
        DefaultHttpClient httpclient = new DefaultHttpClient();
        HttpGet httpGet = new HttpGet("http://www.baidu.com");
        String body = "";
        HttpResponse response;
        HttpEntity entity;
        response = httpclient.execute(httpGet);
        entity = response.getEntity();
        body = EntityUtils.toString(entity);//這個就是頁面源碼了
        httpGet.abort();//中斷請求,接下來能夠開始另外一段請求
        System.out.println(body);
        //httpGet.releaseConnection();//釋放請求.若是釋放了至關於要清空session
        //如下是post方法
        HttpPost httpPost = new HttpPost("http://www.baidu.com");//必定要改爲能夠提交的地址,這裏用百度代替
        List <NameValuePair> nvps = new ArrayList <NameValuePair>();
        nvps.add(new BasicNameValuePair("name", "1"));//名值對
        nvps.add(new BasicNameValuePair("account", "xxxx"));
        httpPost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8));
        response = httpclient.execute(httpPost);
        entity = response.getEntity();
        body = EntityUtils.toString(entity);
        System.out.println("Login form get: " + response.getStatusLine());//這個能夠打印狀態
        httpPost.abort();
        System.out.println(body);
        httpPost.releaseConnection();
    }
}

代碼實例

package http.HttpClient;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;

/**
 * org.apache.http.impl.client.CloseableHttpClient連接池生成工具
 * @reference http://www.cnblogs.com/whatlonelytear/articles/4835538.html
 * @author King
 * @date 20170601
 */
public class HttpClientTool {

    // org.apache.http.impl.client.CloseableHttpClient
    private static CloseableHttpClient httpclient = null;

    // 這裏就直接默認固定了,由於如下三個參數在新建的method中仍然能夠從新配置並被覆蓋.
    static final int connectionRequestTimeout = 5000;// ms毫秒,從池中獲取連接超時時間
    static final int connectTimeout = 5000;// ms毫秒,創建連接超時時間
    static final int socketTimeout = 30000;// ms毫秒,讀取超時時間

    // 總配置,主要涉及是如下兩個參數,若是要做調整沒有用到properties會比較後麻煩,但鑑於一經粘貼,隨處可用的特色,就再也不作依賴性配置化處理了.
    // 並且這個參數同一家公司基本不會變更.
    static final int maxTotal = 500;// 最大總併發,很重要的參數
    static final int maxPerRoute = 100;// 每路併發,很重要的參數

    // 正常狀況這裏應該配成MAP或LIST
    // 細化配置參數,用來對每路參數作精細化處理,能夠管控各ip的流量,好比默認配置請求baidu:80端口最大100個併發連接,
    static final String detailHostName = "http://www.baidu.com";// 每一個細化配置之ip(不重要,在特殊場景頗有用)
    static final int detailPort = 80;// 每一個細化配置之port(不重要,在特殊場景頗有用)
    static final int detailMaxPerRoute = 100;// 每一個細化配置之最大併發數(不重要,在特殊場景頗有用)

    public static CloseableHttpClient getHttpClient() {
        if (null == httpclient) {
            synchronized (HttpClientTool.class) {
                if (null == httpclient) {
                    httpclient = init();
                }
            }
        }
        return httpclient;
    }

    /**
     * 連接池初始化 這裏最重要的一點理解就是. 讓CloseableHttpClient 一直活在池的世界裏, 可是HttpPost卻一直用完就消掉.
     * 這樣可讓連接一直保持着.
     *
     * @return
     */
    private static CloseableHttpClient init() {
        CloseableHttpClient newHttpclient = null;

        // 設置鏈接池
        ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();
        LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory.getSocketFactory();
        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory> create().register("http", plainsf).register("https", sslsf).build();
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
        // 將最大鏈接數增長
        cm.setMaxTotal(maxTotal);
        // 將每一個路由基礎的鏈接增長
        cm.setDefaultMaxPerRoute(maxPerRoute);

        // 細化配置開始,其實這裏用Map或List的for循環來配置每一個連接,在特殊場景頗有用.
        // 將每一個路由基礎的鏈接作特殊化配置,通常用不着
        HttpHost httpHost = new HttpHost(detailHostName, detailPort);
        // 將目標主機的最大鏈接數增長
        cm.setMaxPerRoute(new HttpRoute(httpHost), detailMaxPerRoute);
        // cm.setMaxPerRoute(new HttpRoute(httpHost2),
        // detailMaxPerRoute2);//能夠有細化配置2
        // cm.setMaxPerRoute(new HttpRoute(httpHost3),
        // detailMaxPerRoute3);//能夠有細化配置3
        // 細化配置結束

        // 請求重試處理
        HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() {
            public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
                if (executionCount >= 2) {// 若是已經重試了2次,就放棄
                    return false;
                }
                if (exception instanceof NoHttpResponseException) {// 若是服務器丟掉了鏈接,那麼就重試
                    return true;
                }
                if (exception instanceof SSLHandshakeException) {// 不要重試SSL握手異常
                    return false;
                }
                if (exception instanceof InterruptedIOException) {// 超時
                    return false;
                }
                if (exception instanceof UnknownHostException) {// 目標服務器不可達
                    return false;
                }
                if (exception instanceof ConnectTimeoutException) {// 鏈接被拒絕
                    return false;
                }
                if (exception instanceof SSLException) {// SSL握手異常
                    return false;
                }

                HttpClientContext clientContext = HttpClientContext.adapt(context);
                HttpRequest request = clientContext.getRequest();
                // 若是請求是冪等的,就再次嘗試
                if (!(request instanceof HttpEntityEnclosingRequest)) {
                    return true;
                }
                return false;
            }
        };

        // 配置請求的超時設置
        RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(connectionRequestTimeout).setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout).build();
        newHttpclient = HttpClients.custom().setConnectionManager(cm).setDefaultRequestConfig(requestConfig).setRetryHandler(httpRequestRetryHandler).build();
        return newHttpclient;
    }
}
httpclient實例
import java.io.IOException;
import java.net.UnknownHostException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;

import org.apache.http.HttpEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.message.AbstractHttpMessage;

public class Simplest {
    private void Get() {
        CloseableHttpClient httpclient = HttpClients.createDefault();
        try {
            String HostName = "http://www.baidu.com";
            HttpGet httpget = new HttpGet(HostName);
            System.out.println(httpget.getURI());
            //HttpGet httpget = new HttpGet("http://www.lietu.com");
            CloseableHttpResponse response = httpclient.execute(httpget);
            System.out.println("Successful!");
            System.out.println(response.getProtocolVersion());  //Protocol Version
            System.out.println(response.getStatusLine().getStatusCode());   //Status Code
            System.out.println(response.getStatusLine().getReasonPhrase());
            System.out.println(response.getStatusLine().toString());

            //get entity
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                InputStream input = entity.getContent();
                String filename = HostName.substring(HostName.lastIndexOf('/')+1);
                System.out.println("The filename is: " + filename);
                OutputStream output = new FileOutputStream(filename);

                int tempByte=-1;
                while ((tempByte=input.read())>0) {
                    output.write(tempByte);
                }

                if (input != null) {
                    input.close();
                }

                if (output != null) {
                    output.close();
                }
            }
        } catch(UnknownHostException e) {
            System.out.println("No such a host!");
        } catch(IOException e) {
            e.printStackTrace();
        } 
    }

    public static void main(String[] args) {
        Simplest a = new Simplest();
        a.Get();
        System.out.println("This is a test");
    }
}
相關文章
相關標籤/搜索