HttpClient實現網絡訪問詳解1


1、HttpClient的最常用功能是execute()方法。執行一次execute()會包括了一次或多次request請求 - response響應事件。HttpClient會將request請求發送給目標服務器以取得response響應對象,也可有可能在執行失敗後拋出一個異常。

        一個簡單的代碼如下:

    CloseableHttpClienthttpclient = HttpClients.createDefault();
    HttpGet httpget = newHttpGet("http://localhost/");
    CloseableHttpResponse response = httpclient.execute(httpget);
    try {
        <...>
    } finally {
        response.close();
    }

 

2、所有的Http request請求都包括了一個方法名、一個請求地址和一個HTTP協議版本號。HttpClient支持HTTP/1.1協議下所有的HTTP方法,包括:GetHEADPOSTPUTDELETETRACEOPTIONS。每一種方法都通過特定的類來實現,包括HttpGetHttpHeadHttpPostHttpPutHttpDeleteHttpTraceHttpOptions

   請求地址由一個URI(統一資源定位符)來描述。Http URI包括了協議、主機名、端口、地址、請求參數等。

   例如:

   HttpGet httpget = newHttpGet(
     "http://www.google.com/search?hl=en&q=httpclient&btnG=Google+Search&aq=f&oq=");

 

       HttpClient 提供了URIBuilder類來簡化請求地址的創建和修改,例如:

   URI uri = newURIBuilder()
           .setScheme("http")
           .setHost("www.google.com")
           .setPath("/search")
           .setParameter("q","httpclient")
           .setParameter("btnG","Google Search")
           .setParameter("aq","f")
           .setParameter("oq","")
           .build();
    HttpGet httpget = new HttpGet(uri);
    System.out.println(httpget.getURI());

 

    輸出:

    http://www.google.com/search?q=httpclient&btnG=Google+Search&aq=f&oq=

 

 

3、Httpresponse是服務器返回給客戶端的一段報文。報文的第一行包括了協議版本、數字狀態碼和文字描述。例如:

    HttpResponse response= new BasicHttpResponse(HttpVersion.HTTP_1_1,
                            HttpStatus.SC_OK, "OK");

    System.out.println(response.getProtocolVersion());
    System.out.println(response.getStatusLine().getStatusCode());
    System.out.println(response.getStatusLine().getReasonPhrase());
    System.out.println(response.getStatusLine().toString());

 

4、一Http報文包括了多個header描述屬性,包括內容長度、內容類型等等,HttpClient提供了查詢、刪除、處理header的方法,例如:

 

    HttpResponse response= new BasicHttpResponse(HttpVersion.HTTP_1_1,
                            HttpStatus.SC_OK,"OK");
    response.addHeader("Set-Cookie",
                            "c1=a; path=/;domain=localhost");
    response.addHeader("Set-Cookie",
                            "c2=b; path=\"/\",c3=c; domain=\"localhost\"");
    Header h1 = response.getFirstHeader("Set-Cookie");
    System.out.println(h1);
    Header h2 =response.getLastHeader("Set-Cookie");
    System.out.println(h2);
    Header[] hs =response.getHeaders("Set-Cookie");
    System.out.println(hs.length);

 

    輸出:

    Set-Cookie: c1=a;path=/; domain=localhost
    Set-Cookie: c2=b; path="/", c3=c; domain="localhost"
    2

 

    最有效率的做法是用HeaderIterator來獲得特定類型的所有header

    例如:

 

    HttpResponse response= new BasicHttpResponse(HttpVersion.HTTP_1_1,
                           HttpStatus.SC_OK,"OK");
    response.addHeader("Set-Cookie",
                            "c1=a; path=/;domain=localhost");
    response.addHeader("Set-Cookie",
                            "c2=b; path=\"/\",c3=c; domain=\"localhost\"");

    HeaderIterator it =response.headerIterator("Set-Cookie");

    while (it.hasNext()){
            System.out.println(it.next());
    }

 

    輸出:

 

    Set-Cookie: c1=a;path=/; domain=localhost
    Set-Cookie: c2=b; path="/", c3=c; domain="localhost"

 

5、HttpEntity 是Http request-reponse交互的報文內容。HttpClient區分了三種報文內容:

    (1)流形式的報文內容,報文內容不可重複。

    (2)獨立的報文內容,報文內容是可重複的。

    (3)從其他報文內容中獲取的報文內容。

 

    通過HttpEntitygetContent()可以獲得Java.io.Inputstream的輸入流,也可以通過HttpEntitywriteTo(OutputStream)寫入內容。

         HttpEntitygetContentType()getContentLength()方法可以獲取Content-TypeContent-Length的元數據,getContentEncoding()方法可以獲取編碼格式。

    例如:

    StringEntity myEntity= new StringEntity("important message",
    ContentType.create("text/plain", "UTF-8"));

    System.out.println(myEntity.getContentType());
    System.out.println(myEntity.getContentLength());
    System.out.println(EntityUtils.toString(myEntity));
    System.out.println(EntityUtils.toByteArray(myEntity).length);

 

    輸出:

     Content-Type:text/plain; charset=utf-8
    17
    important message
    17

 

    讀取HttpEntity,例如:

    CloseableHttpClienthttpclient = HttpClients.createDefault();
    HttpGet httpget = newHttpGet("http://localhost/");
    CloseableHttpResponse response = httpclient.execute(httpget);
    try {
        HttpEntity entity =response.getEntity();
        if (entity != null) {
            long len =entity.getContentLength();
            if (len != -1 && len <2048) {
               System.out.println(EntityUtils.toString(entity));
            } else {
                // Stream contentout
            }
        }
    } finally {
        response.close();
    }

 

    也可以生成報文內容

    File file = newFile("somefile.txt");
    FileEntity entity = new FileEntity(file,
                       ContentType.create("text/plain", "UTF-8"));       

    HttpPost httppost =newHttpPost("http://localhost/action.do");
    httppost.setEntity(entity);


6、可以通過UrlEncodeFormEntity來提交表單,例如

    List<NameValuePair>formparams = new ArrayList<NameValuePair>();
    formparams.add(new BasicNameValuePair("param1","value1"));
    formparams.add(new BasicNameValuePair("param2","value2"));
    UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams,Consts.UTF_8);
    HttpPost httppost = newHttpPost("http://localhost/handler.do");
    httppost.setEntity(entity);

 

 

7、可以採用ResponseHandler來簡化連接操作,例如

 

    CloseableHttpClienthttpclient = HttpClients.createDefault();
    HttpGet httpget = new HttpGet("http://localhost/json");

    ResponseHandler<MyJsonObject>rh = new ResponseHandler<MyJsonObject>() {

        @Override
        public JsonObjecthandleResponse(
                final HttpResponse response)throws IOException {
            StatusLine statusLine =response.getStatusLine();
            HttpEntity entity =response.getEntity();
            if (statusLine.getStatusCode()>= 300) {
                throw newHttpResponseException(
                   statusLine.getStatusCode(),
                    statusLine.getReasonPhrase());
            }
            if (entity == null) {
                throw newClientProtocolException("Response contains no content");
            }
            Gson gson = newGsonBuilder().create();
            ContentType contentType =ContentType.getOrDefault(entity);
            Charset charset =contentType.getCharset();
            Reader reader = newInputStreamReader(entity.getContent(), charset);
            return gson.fromJson(reader,MyJsonObject.class);
        }
    };
    MyJsonObject myjson = client.execute(httpget, rh);

 

 

8、 httpClient不是線程安全的,所以如果不再使用的話,可以通過close()方法進行關閉,例如

 

    CloseableHttpClienthttpclient = HttpClients.createDefault();
    try {
        <...>
    } finally {
            httpclient.close();
}

 

9、HttpContext可以作爲Http交互的上下文,是以java.util.Map存儲的對象。包括了HttpConnectionHttpHostHttpRouteHttpRequest等,可以通過HttpclientContext來定義上下文狀態。

    HttpContext context =<...>
    HttpClientContext clientContext =HttpClientContext.adapt(context);
    HttpHost target = clientContext.getTargetHost();
    HttpRequest request = clientContext.getRequest();
    HttpResponse response = clientContext.getResponse();
    RequestConfig config = clientContext.getRequestConfig();

 

 10、如果要實現重試機制,可以採用HttpRequestRetryHandler接口來實現。例如:

    HttpRequestRetryHandlermyRetryHandler = new HttpRequestRetryHandler() {

    public booleanretryRequest(
                IOExceptionexception,
                intexecutionCount,
                HttpContext context){
        if (executionCount >= 5){
            // Do not retry if over maxretry count
            return false;
        }
        if (exception instanceofInterruptedIOException) {
            // Timeout
            return false;
        }
        if (exception instanceofUnknownHostException) {
            // Unknown host
            return false;
        }
        if (exception instanceofConnectTimeoutException) {
            // Connectionrefused
            return false;
        }
        if (exception instanceofSSLException) {
            // SSL handshakeexception
            return false;
        }
        HttpClientContext clientContext =HttpClientContext.adapt(context);
        HttpRequest request =clientContext.getRequest();
        boolean idempotent = !(requestinstanceof HttpEntityEnclosingRequest);
        if (idempotent) {
            // Retry if the request isconsidered idempotent
            return true;
        }
            return false;
        }

    };
    CloseableHttpClient httpclient = HttpClients.custom()
               .setRetryHandler(myRetryHandler)
                .build();

 

 

11、重定向處理,例如:

 

    CloseableHttpClienthttpclient = HttpClients.createDefault();
    HttpClientContext context = HttpClientContext.create();
    HttpGet httpget = newHttpGet("http://localhost:8080/");
    CloseableHttpResponse response = httpclient.execute(httpget, context);
    try {
        HttpHost target =context.getTargetHost();
        List<URI> redirectLocations =context.getRedirectLocations();
        URI location =URIUtils.resolve(httpget.getURI(), target, redirectLocations);
        System.out.println("Final HTTPlocation: " + location.toASCIIString());
        // Expected to be an absoluteURI
    } finally {
        response.close();
    }


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章