1. 程式人生 > >java 反編譯 知識學習彙總 java網路爬取網頁程式碼

java 反編譯 知識學習彙總 java網路爬取網頁程式碼

以下文章可能有參考別人的程式碼而彙總的內容  請各位大俠合作愉快     借鑑一下

http://blog.csdn.net/qq_26891045/article/details/52517585

http://blog.csdn.net/dongnan591172113/article/details/51832628

http://www.360doc.com/content/14/0328/03/13017437_364313510.shtml

http://blog.csdn.net/r3t7o7/article/details/57074722

http://www.cnblogs.com/hoojo/archive/2013/04/12/3016516.html

http://blog.csdn.net/onafioo/article/details/49923827

http://www.knowsky.com/367400.html

https://bbs.pediy.com/thread-51945.htm

http://www.360doc.com/content/14/0328/03/13017437_364313510.shtml

http://blog.csdn.net/enweitech/article/details/51849049

http://yongkuang.iteye.com/blog/1172100

http://www.myexception.cn/java-web/42304.html

https://item.taobao.com/item.htm?spm=a230r.1.14.53.34d59246nH0FYS&id=558588943852&ns=1&abbucket=5#detail

http://blog.csdn.net/kongwei521/article/details/54927689

https://zhidao.baidu.com/question/165093593.html

https://s.taobao.com/search?q=.net+%E5%8F%8D%E7%BC%96%E8%AF%91&imgfile=&js=1&stats_click=search_radio_all%3A1&initiative_id=staobaoz_20170921&ie=utf8

https://item.taobao.com/item.htm?spm=a230r.1.14.44.4e9ae445cQsYdX&id=556004656489&ns=1&abbucket=5#detail

http://blog.csdn.net/dianacody/article/details/39584977   很好的

http://blog.csdn.net/wangpeng047/article/details/19624529

=================================================================

package pachong;


import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;

public class CrawlerUtil {

/*
* 獲取原始碼
*/
public static String getHtmlSource(String url){

InputStream inputStream = null;
BufferedReader in = null;
StringBuilder htmlSource= new StringBuilder();

try {
//1.獲取網址
URL u = new URL(url);
//2.開啟連線
URLConnection conn = u.openConnection();
//3.獲取輸入流
inputStream = conn.getInputStream();
//4.將原始碼寫入記憶體(設定編碼)
in = new BufferedReader(new InputStreamReader(inputStream,"utf-8"));
String str = "";
while((str = in.readLine()) != null){
htmlSource.append(str);
}
} catch (Exception e) {
e.printStackTrace();
}finally{
//關閉I/o
try {
if(in != null)in.close();
if(inputStream != null)inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}

}
return htmlSource.toString();
}


public static void main(String[] args) {

String url = "http://www.mnkjxy.com/";
System.out.println(getHtmlSource(url));
}
}

說明: 

前者經常使用  ,在確定了URL的物件 指向的絕對是文字且編碼格式為ASCII時

後者 可以生產連線物件,呼叫其它方法做一些事情功能使用。

=======================================================

下面轉載httpclient ,感謝下面這位大咔 

http://blog.csdn.net/wangpeng047/article/details/19624529

http://blog.csdn.net/witsmakemen/article/details/12003793

傳遞引數:給伺服器 ,  在測試返回的資料

TestingCode:

//建立預設的httpClient例項.

HttpClient httpclient = new DefaultHttpClient();

//建立httppost

HttpPost httppost = new HttpPost("http://localhost:8080/myDemo/Ajax/serivceJ.action");

//建立引數佇列

List<NameValuePair> formparams = new ArrayList<NameValuePair>();

formparams.add(new BasicNameValuePair("type", "house"));

UrlEncodedFormEntity uefEntity;

try {

    uefEntity = new UrlEncodedFormEntity(formparams, "UTF-8");

    httppost.setEntity(uefEntity);

    System.out.println("executing request " + httppost.getURI());

    HttpResponse response;

    response = httpclient.execute(httppost);

    HttpEntity entity = response.getEntity();

if (entity != null) {        System.out.println("--------------------------------------");

    System.out.println("Response content: " + EntityUtils.toString(entity,"UTF-8"));

System.out.println("--------------------------------------");

           }

       } catch (ClientProtocolException e) {

           e.printStackTrace();

       }catch(UnsupportedEncodingException e1) {

           e1.printStackTrace();

       }catch (IOException e) {

           e.printStackTrace();

       }finally{

             //關閉連線,釋放資源

           httpclient.getConnectionManager().shutdown();

       }

輸出:


模擬表單登陸:

TestingCode:

//建立預設的httpClient例項.

HttpClient httpclient = new DefaultHttpClient();

//建立httppost

HttpPost httppost = new HttpPost("http://localhost:8080/myDemo/Ajax/serivceJ.action");

//建立引數佇列

List<NameValuePair> formparams = new ArrayList<NameValuePair>();

formparams.add(new BasicNameValuePair("username", "admin"));

formparams.add(new BasicNameValuePair("password", "123456"));

UrlEncodedFormEntity uefEntity;

try {

    uefEntity = new UrlEncodedFormEntity(formparams, "UTF-8");

    httppost.setEntity(uefEntity);

    System.out.println("executing request " + httppost.getURI());

    HttpResponse response;

    response = httpclient.execute(httppost);

    HttpEntity entity = response.getEntity();

if (entity != null) {        System.out.println("--------------------------------------");

    System.out.println("Response content: " + EntityUtils.toString(entity,"UTF-8"));

System.out.println("--------------------------------------");

           }

       } catch (ClientProtocolException e) {

           e.printStackTrace();

       }catch(UnsupportedEncodingException e1) {

           e1.printStackTrace();

       }catch (IOException e) {

           e.printStackTrace();

       }finally{

             //關閉連線,釋放資源

           httpclient.getConnectionManager().shutdown();

       }

會將返回的jsp輸出:


--------------------------------------------------------------

package pachong;

import java.io.IOException;
import java.net.URISyntaxException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

/*
import java.io.BufferedReader;  
import java.io.BufferedWriter;  
import java.io.File;  
import java.io.FileReader;  
import java.io.FileWriter;  
import java.io.IOException;  
import java.net.URI;  
import java.net.URISyntaxException;  
import java.util.regex.Pattern;  
import java.util.regex.Matcher;  
 
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.CookieSpecs;  
import org.apache.http.client.config.RequestConfig;  
import org.apache.http.client.methods.CloseableHttpResponse;  
import org.apache.http.client.methods.HttpGet;  
import org.apache.http.config.Registry;  
import org.apache.http.config.RegistryBuilder;  
import org.apache.http.cookie.Cookie;  
import org.apache.http.cookie.CookieOrigin;  
import org.apache.http.cookie.CookieSpec;  
import org.apache.http.cookie.CookieSpecProvider;  
import org.apache.http.cookie.MalformedCookieException;  
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClients;  
import org.apache.http.impl.cookie.BestMatchSpecFactory;  
import org.apache.http.impl.cookie.BrowserCompatSpec;  
import org.apache.http.impl.cookie.BrowserCompatSpecFactory;  
import org.apache.http.protocol.HttpContext;  
import org.apache.http.util.EntityUtils;  
 
 
  */

public class Weibo163
{

    public static void main(String[] args) throws IOException, URISyntaxException, InterruptedException
    {

        HttpClient httpclient = new DefaultHttpClient();

        try
        {

            HttpGet httpget = new HttpGet("http://www.baidu.com");
            System.out.println("executing request " + httpget.getURI());

            HttpResponse response = httpclient.execute(httpget);

            // 列印響應狀態
            System.out.println(response.getStatusLine());

            System.out.println("--------------------------------------");

            // 獲取響應實體
            HttpEntity entity = response.getEntity();

            
            if (entity != null)
            {
                // 列印響應內容長度
                System.out.println("Response content length: " + entity.getContentLength());

                // 列印響應內容
                System.out.println("Response content: " + EntityUtils.toString(entity,"UTF-8"));
            }
            System.out.println("------------------------------------");

        } finally
        {

            // 關閉連線,釋放資源

            httpclient.getConnectionManager().shutdown();

        }
    }

}

===========================================

自己寫的 讀取網頁資料的 模板程式碼:

package pachong2;

import java.io.IOException;

import org.apache.http.HttpEntity;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import pachong.Almanac;

public class TestHtml
{
    public TestHtml()
    {
        
    }

    private static void doTask(String url)
    {
        String html = pickData(url);
        String s1  = analyzeHtml(html);
        System.out.println(s1);
        // String s2  = analyzeHtml(html);
    }

    // 爬取網頁全部資料 getHtmlEntity
    private static String pickData(String url)
    {
        CloseableHttpClient httpclient = HttpClients.createDefault();
        try
        {
            HttpGet httpget = new HttpGet(url);
            CloseableHttpResponse response = httpclient.execute(httpget);
            try
            {
                // 獲取響應實體
                HttpEntity entity = response.getEntity();
                // 列印響應狀態
                if (entity != null)
                {
                    return EntityUtils.toString(entity);
                }
            } finally
            {
                response.close();
            }
        } catch (ClientProtocolException e)
        {
            e.printStackTrace();
        } catch (ParseException e)
        {
            e.printStackTrace();
        } catch (IOException e)
        {
            e.printStackTrace();
        } finally
        {
            // 關閉連線,釋放資源
            try
            {
                httpclient.close();
            } catch (IOException e)
            {
                e.printStackTrace();
            }
        }
        return null;
    }

    // 解析網頁中的元素與資料,提取出來。
    private static String analyzeHtml(String html)
    {
        org.jsoup.nodes.Document document = Jsoup.parse(html);
        
        String a, b, c,d="";        
    //    Element element =document.getElementById(" 此處輸入某一個網頁標籤程式碼 id=** ");
      //  a =  element.text().toString();  //獲取標籤的值了
        
        
        b = analyzeHtml(document, "Layer2");

        //b = analyzeHtml(document, "__01");
        return b;
        /*
        String solarDate, lunarDate, chineseAra, should, avoid = " ";
        org.jsoup.nodes.Document document = Jsoup.parse(html);
        // 公曆時間
        //solarDate = getSolarDate();
        // 農曆時間
        Element eLunarDate = document.getElementById("info_nong");
        lunarDate = eLunarDate.child(0).html().substring(1, 3) + eLunarDate.html().substring(11);
        // 天干地支紀年法
        Element eChineseAra = document.getElementById("info_chang");
        chineseAra = eChineseAra.text().toString();
        // 宜
    //    should = getSuggestion(document, "yi");
        // 忌
    //    avoid = getSuggestion(document, "ji");
    //    Almanac almanac = new Almanac(solarDate, lunarDate, chineseAra, should, avoid);
        return almanac;
        */
        
    }

     private static String analyzeHtml(org.jsoup.nodes.Document document,String id){
            Element element=document.getElementById(id);
            Elements elements=element.getElementsByTag("a");
            StringBuffer sb=new StringBuffer();
            for (Element e : elements) {
                sb.append(e.text()+" ");
            }
            return sb.toString();
        }
    
    
    public static void main(String[] args)
    {

        
        TestHtml.doTask("http://www.mnkjxy.com/html/xwzx/xyxw/");    

        
        

    }

}




===============================


httpclient學習知識彙總:


HttpClient 不是一個瀏覽器。它是一個客戶端的 HTTP 通訊實現庫。 HttpClient 的目
標是傳送和接收 HTTP 報文。

HttpClient 最重要的功能是執行 HTTP 方法。一個 HTTP 方法的執行包含一個或多個 HTTP請求/HTTP 響應交換,通常由 HttpClient 的內部來處理。而期望使用者提供一個要執行的請求物件,而 HttpClient 期望傳輸請求到目標伺服器並返回對應的響應物件,或者當執行不成功時丟擲異常。


HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet("http://localhost/");
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
int l;
byte[] tmp = new byte[2048];
while ((l = instream.read(tmp)) != -1) {
}
}

------------------------------------------------------------------

HTTP 請求

HttpClient 提供很多工具方法來簡化建立和修改執行 URI。URI 也可以程式設計來拼裝:
URI uri = URIUtils.createURI("http", "www.google.com", -1,
"/search",
"q=httpclient&btnG=Google+Search&aq=f&oq=", null);
HttpGet httpget = new HttpGet(uri);
System.out.println(httpget.getURI());

查詢字串也可以從獨立的引數中來生成:
List<NameValuePair> qparams = new ArrayList<NameValuePair>();
qparams.add(new BasicNameValuePair("q", "httpclient"));
qparams.add(new BasicNameValuePair("btnG", "Google Search"));
qparams.add(new BasicNameValuePair("aq", "f"));
qparams.add(new BasicNameValuePair("oq", null));
URI uri = URIUtils.createURI("http", "www.google.com", -1,
"/search",
URLEncodedUtils.format(qparams, "UTF-8"), null);
HttpGet httpget = new HttpGet(uri);
System.out.println(httpget.getURI());


HTTP 響應:HTTP 響應是由伺服器在接收和解釋請求報文之後返回傳送給客戶端的報文。響應報文
的第一行包含了協議版本,之後是數字狀態碼和相關聯的文字段。
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());


處理報文頭部
一個 HTTP 報文可以包含很多描述如內容長度,內容型別等資訊屬性的頭部資訊。
HttpClient 提供獲取,新增,移除和列舉頭部資訊的方法。
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);

獲得給定型別的所有頭部資訊最有效的方式是使用 HeaderIterator 介面。
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());
}

它也提供解析 HTTP 報文到獨立頭部資訊元素的方法方法。
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\"");
HeaderElementIterator it = new BasicHeaderElementIterator(
response.headerIterator("Set-Cookie"));
while (it.hasNext()) {
HeaderElement elem = it.nextElement();
System.out.println(elem.getName() + " = " +
elem.getValue());
NameValuePair[] params = elem.getParameters();
for (int i = 0; i < params.length; i++) {
System.out.println(" " + params[i]);
}
}

HTTP 實體
HTTP 報文可以攜帶和請求或響應相關的內容實體。實體可以在一些請求和響應中找到,因為它們也是可選的。使用了實體的請求被稱為封閉實體請求。 HTTP 規範定義了兩種封閉實體的方法: POST 和 PUT。響應通常期望包含一個內容實體。這個規則也有特例,比如HEAD 方法的響應和 204 No Content, 304 Not Modified 和 205 Reset Content響應。
HttpClient 根據其內容出自何處區分三種類型的實體:
? streamed 流式:內容從流中獲得,或者在執行中產生。特別是這種分類包含從 HTTP響應中獲取的實體。流式實體是不可重複生成的。
? self-contained 自我包含式:內容在記憶體中或通過獨立的連線或其它實體中獲得。自我包含式的實體是可以重複生成的。這種型別的實體會經常用於封閉 HTTP 請求的實體。
? wrapping 包裝式:內容從另外一個實體中獲得。

重複實體
實體可以重複,意味著它的內容可以被多次讀取。這就僅僅是自我包含式的實體了(像ByteArrayEntity 或 StringEntity)。


使用 HTTP 實體
因為一個實體既可以代表二進位制內容又可以代表字元內容,它也支援字元編碼(支援後者也就是字元內容)。實體是當使用封閉內容執行請求,或當請求已經成功執行,或當響應體結果發功到客戶端時建立的。
要從實體中讀取內容,可以通過 HttpEntity#getContent()方法從輸入流中獲取,這 會 返 回 一 個 java.io.InputStream 對 象 , 或 者 提 供 一 個 輸 出 流 到HttpEntity#writeTo(OutputStream)方法中,這會一次返回所有寫入到給定流中的內容。
當實體通過一個收到的報文獲取時, HttpEntity#getContentType()方法和
HttpEntity#getContentLength() 方 法 可 以 用 來 讀 取 通 用 的 元 數 據 , 如
Content-Type 和 Content-Length 頭部資訊(如果它們是可用的)。因為頭部資訊
Content-Type 可以包含對文字 MIME 型別的字元編碼,比如 text/plain 或 text/html,HttpEntity#getContentEncoding()方法用來讀取這個資訊。 如果頭部資訊不可用,那麼就返回長度-1,而對於內容型別返回 NULL。如果頭部資訊 Content-Type 是可用的,那麼就會返回一個 Header 物件。

當為一個傳出報文建立實體時,這個元資料不得不通過實體建立器來提供。
StringEntity myEntity = new StringEntity("important message","UTF-8");
System.out.println(myEntity.getContentType());
System.out.println(myEntity.getContentLength());
System.out.println(EntityUtils.getContentCharSet(myEntity));
System.out.println(EntityUtils.toString(myEntity));
System.out.println(EntityUtils.toByteArray(myEntity).length);

輸出內容為
Content-Type: text/plain; charset=UTF-8
17
UTF-8
important message
17

也可能會有特殊情況,當整個響應內容的一小部分需要獲取,消耗剩餘內容而損失效能,還有重用連線的代價太高,則可以僅僅通過呼叫 HttpUriRequest#abort()方法來中止請求。
HttpGet httpget = new HttpGet("http://localhost/");
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
int byteOne = instream.read();
int byteTwo = instream.read();
// Do not need the rest
httpget.abort();
}

HttpClient 也自帶 EntityUtils 類,這會暴露出一些靜態方法,這些方法可以更加容易地從實體中讀取內容或資訊。代替直接讀取 java.io.InputStream, 也可以使用這個類中的方法以字串/位元組陣列的形式獲取整個內容體。然而, EntityUtils 的使用是強烈不鼓勵的,除非響應實體源自可靠的 HTTP伺服器和已知的長度限制。
HttpGet httpget = new HttpGet("http://localhost/");
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
if (entity != null) {
long len = entity.getContentLength();
if (len != -1 && len < 2048) {
System.out.println(EntityUtils.toString(entity));
} else {
// Stream content out
}
}

在一些情況下可能會不止一次的讀取實體。此時實體內容必須以某種方式在記憶體或磁碟上被緩衝起來。最簡單的方法是通過使用 BufferedHttpEntity 類來包裝源實體完成。這會引起源實體內容被讀取到記憶體的緩衝區中。在其它所有方式中,實體包裝器將會得到源實體。
HttpGet httpget = new HttpGet("http://localhost/");
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
if (entity != null) {
entity = new BufferedHttpEntity(entity);
}


生成實體內容
HttpClient 提供一些類,它們可以用於生成通過 HTTP 連接獲得內容的有效輸出流。為了封閉實體從 HTTP 請求中獲得的輸出內容,那些類的例項可以和封閉如 POST 和 PUT 請求的實體相關聯。 HttpClient 為很多公用的資料容器,比如字串,位元組陣列,輸入流和檔案提供了一些類: StringEntity, ByteArrayEntity, InputStreamEntity 和FileEntity。
example:
File file = new File("somefile.txt");
FileEntity entity = new FileEntity(file, "text/plain;
charset=\"UTF-8\"");
HttpPost httppost = new HttpPost("http://localhost/action.do");
httppost.setEntity(entity);


動態內容實體
通常來說 , HTTP 實體 需要基於 特定的 執行上 下文來 動態地生 成。通 過使用
EntityTemplate 實體類和 ContentProducer 介面, HttpClient 提供了動態實體的支
持。 內容生成器是按照需求生成它們內容的物件,將它們寫入到一個輸出流中。 它們是每次被請求時來生成內容。所以用 EntityTemplate 建立的實體通常是自我包含而且可以重複的。
ContentProducer cp = new ContentProducer() {
public void writeTo(OutputStream outstream) throws IOException {
Writer writer = new OutputStreamWriter(outstream, "UTF-8");
writer.write("<response>");
writer.write(" <content>");
writer.write(" important stuff");
writer.write(" </content>");
writer.write("</response>");
writer.flush();
}
};

HttpEntity entity = new EntityTemplate(cp);
HttpPost httppost = new HttpPost("http://localhost/handler.do");
httppost.setEntity(entity);

HTML 表單:
許多應用程式需要頻繁模擬提交一個 HTML 表單的過程,比如,為了來記錄一個 Web應用程式或提交輸出資料。 HttpClient 提供了特殊的實體類 UrlEncodedFormEntity 來這個滿足過程。

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

param1=value1&param2=value2


內容分塊
我們推薦讓 HttpClient 選擇基於被傳遞的 HTTP 報文屬性的最適合的編碼轉換。
這是可能的,但是,設定 HttpEntity#setChunked()方法為 true 是通知 HttpClient 分
塊編碼的首選。 請注意 HttpClient 將會使用標識作為提示。當使用的 HTTP 協議版本,如HTTP/1.0 版本,不支援分塊編碼時,這個值會被忽略。
StringEntity entity = new StringEntity("important message","text/plain; charset=\"UTF-8\"");
entity.setChunked(true);
HttpPost httppost = new
HttpPost("http://localhost/acrtion.do");
httppost.setEntity(entity);


響應控制器:
控制響應的最簡便和最方便的方式是使用 ResponseHandler 介面。這個放完完全減
輕了使用者關於連線管理的擔心。當使用 ResponseHandler 時, HttpClient 將會自動關注並保證釋放連線到連線管理器中去,而不管請求執行是否成功或引發了異常。

HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet("http://localhost/");
ResponseHandler<byte[]> handler = new  ResponseHandler<byte[]>() {
public byte[] handleResponse(HttpResponse response) throws ClientProtocolException,
IOException {
HttpEntity entity = response.getEntity();
if (entity != null) {
return EntityUtils.toByteArray(entity);
} else {
return null;
}
}
};
byte[] response = httpclient.execute(httpget, handler);

HTTP 執行的環境:
HTTP是被設計成無狀態的,面向請求-響應的協議。然而,真實的應用程式經常
需要通過一些邏輯相關的請求-響應交換來持久狀態資訊。 為了開啟應用程式來維持一個過程狀態, HttpClient允許HTTP請求在一個特定的執行環境中來執行, 簡稱為HTTP上下文。

HttpClient添加了下列屬性到執行上下文中:
? 'http.connection': HttpConnection例項代表了連線到目標伺服器的真實連線。
? 'http.target_host': HttpHost例項代表了連線目標。
? 'http.proxy_host': 如果使用了, HttpHost例項代表了代理連線。
? 'http.request': HttpRequest 例項代表了真實的 HTTP 請求。
? 'http.response': HttpResponse 例項代表了真實的 HTTP 響應。
? 'http.request_sent': java.lang.Boolean 物件代表了暗示真實請求是否被完
全傳送到目標連線的標識。
比如,為了決定最終的重定向目標,在請求執行之後,可以檢查 http.target_host
屬性的值:

DefaultHttpClient httpclient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpGet httpget = new HttpGet("http://www.google.com/");
HttpResponse response = httpclient.execute(httpget,
localContext);
HttpHost target = (HttpHost) localContext.getAttribute(
ExecutionContext.HTTP_TARGET_HOST);
System.out.println("Final target: " + target);
HttpEntity entity = response.getEntity();
if (entity != null) {
entity.consumeContent();
}
輸出內容是:
Final target: http://www.google.ch


請求重試處理:
為了開啟自定義異常恢復機制,應該提供一個 HttpRequestRetryHandler 介面的
實現。
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() {
public boolean retryRequest(IOException exception,
int executionCount,HttpContext context) {
if (executionCount >= 5) {
// 如果超過最大重試次數,那麼就不要繼續了
return false;
}
if (exception instanceof NoHttpResponseException) {
// 如果伺服器丟掉了連線,那麼就重試
return true;
}
if (exception instanceof SSLHandshakeException) {
// 不要重試SSL握手異常
return false;
}
HttpRequest request = (HttpRequest) context.getAttribute(
ExecutionContext.HTTP_REQUEST);
boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
if (idempotent) {
// 如果請求被認為是冪等的,那麼就重試
return true;
}
return false;
}
};
httpclient.setHttpRequestRetryHandler(myRetryHandler);


HTTP 引數:
HttpParams 介面代表了定義元件執行時行為的一個不變的值的集合。很多情況下,
HttpParams 和 HttpContext 相似。二者之間的主要區別是它們在執行時使用的不同。這兩個介面表示了物件的集合,它們被視作為訪問物件值的鍵的 Map,但是服務於不同的目的:
? HttpParams 旨在包含簡單物件:整型,浮點型,字串,集合,還有執行時不變的物件。
? HttpParams 希望被用在“一次寫入-多處準備”模式下。 HttpContext 旨在包含很可能在 HTTP 報文處理這一過程中發生改變的複雜物件
? HttpParams 的目標是定義其它元件的行為。通常每一個複雜的元件都有它自己的HttpParams 物件。 HttpContext 的目標是來表示一個 HTTP 處理的執行狀態。通
常相同的執行上下文在很多合作的物件中共享。

在 HTTP 請求執行過程中, HttpRequest 物件的 HttpParams 是和用於執行請求的
HttpClient 例項的 HttpParams 聯絡在一起的。這使得設定在 HTTP 請求級別的引數優先於設定在 HTTP客戶端級別的HttpParams。推薦的做法是設定普通引數對所有的在 HTTP客戶端級別的 HTTP 請求共享,而且可以選擇性重寫具體在 HTTP 請求級別的引數。

DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.getParams().setParameter(CoreProtocolPNames.PROTO
COL_VERSION,HttpVersion.HTTP_1_0);
httpclient.getParams().setParameter(CoreProtocolPNames.HTTP_
CONTENT_CHARSET,"UTF-8");
HttpGet httpget = new HttpGet("http://www.google.com/");
httpget.getParams().setParameter(CoreProtocolPNames.PROTOCOL
_VERSION,HttpVersion.HTTP_1_1);
httpget.getParams().setParameter(CoreProtocolPNames.USE_EXPE
CT_CONTINUE,Boolean.FALSE);
httpclient.addRequestInterceptor(new
HttpRequestInterceptor() {

public void process(final HttpRequest request,
final HttpContext context) throws HttpException, IOException {
System.out.println(request.getParams().getParameter(
CoreProtocolPNames.PROTOCOL_VERSION));
System.out.println(request.getParams().getParameter(
CoreProtocolPNames.HTTP_CONTENT_CHARSET));
System.out.println(request.getParams().getParameter(
CoreProtocolPNames.USE_EXPECT_CONTINUE));
System.out.println(request.getParams().getParameter(
CoreProtocolPNames.STRICT_TRANSFER_ENCODING));
}
});


輸出內容為:
HTTP/1.1
UTF-8
false
null


HTTP 引數 bean:
HttpParams 介面允許在處理元件的配置上很大的靈活性。很重要的是,新的引數可
以被引入而不會影響老版本的二進位制相容性。然而,和常規的 Java bean 相比, HttpParams也有一個缺點: HttpParams 不能使用 DI 框架來組合。為了緩解這個限制, HttpClient 包含了一些 bean 類,它們可以用來按順序使用標準的 Java eban 慣例初始化 HttpParams 物件。

HttpParams params = new BasicHttpParams();
HttpProtocolParamBean paramsBean = new
HttpProtocolParamBean(params);
paramsBean.setVersion(HttpVersion.HTTP_1_1);
paramsBean.setContentCharset("UTF-8");
paramsBean.setUseExpectContinue(true);
System.out.println(params.getParameter(
CoreProtocolPNames.PROTOCOL_VERSION));
System.out.println(params.getParameter(
CoreProtocolPNames.HTTP_CONTENT_CHARSET));
System.out.println(params.getParameter(
CoreProtocolPNames.USE_EXPECT_CONTINUE));
System.out.println(params.getParameter(
CoreProtocolPNames.USER_AGENT));


HTTP 請求執行引數
這些引數會影響到請求執行的過程:
? 'http.protocol.version':如果沒有在請求物件中設定明確的版本資訊,它就定義了
使用的 HTTP 協議版本。這個引數期望得到一個 ProtocolVersion 型別的值。
如果這個引數沒有被設定,那麼就使用 HTTP/1.1。
? 'http.protocol.element-charset': 定義了編碼 HTTP 協議元素的字符集。這個引數期望得到一個 java.lang.String 型別的值。如果這個引數沒有被設定,那麼就
使用 US-ASCII。 'http.protocol.eontent-charset': 定義了為每個內容主體編碼的預設字符集。這個引數期望得到一個 java.lang.String 型別的值。如果這個引數沒有被設定,那麼就使用 ISO-8859-1。
? 'http.useragent': 定義了頭部資訊 User-Agent 的內容。這個引數期望得到一個
java.lang.String 型別的值。如果這個引數沒有被設定,那麼 HttpClient 將會
為它自動生成一個值。
? 'http.protocol.strict-transfer-encoding': 定義了響應頭部資訊中是否含有一個非法
的 Transfer-Encoding,都要拒絕掉。
? 'http.protocol.expect-continue' : 為 包 含 方 法 的 實 體 激 活 Expect:
100-Continue 握手。 Expect: 100-Continue 握手的目的是允許客戶端使
用請求體傳送一個請求資訊來決定源伺服器是否希望在客戶端傳送請求體之前得
到這個請求(基於請求頭部資訊)。 Expect: 100-Continue 握手的使用可以
對需要目標伺服器認證的包含請求的實體(比如 POST 和 PUT)導致明顯的效能
改善。 Expect: 100-Continue 握手應該謹慎使用,因為它和 HTTP 伺服器,
不 支 持 HTTP/1.1 協 議的 代 理使 用會 引 起問 題 。這 個參 數 期望 得到 一 個
java.lang.Boolean 型別的值。如果這個引數沒有被設定,那麼 HttpClient 將
會試圖使用握手。
? 'http.protocol.wait-for-continue': 定義了客戶端應該等待 100-Continue 響應最
大的毫秒級時間間隔。這個引數期望得到一個 java.lang.Integer 型別的值。
如果這個引數沒有被設定,那麼 HttpClient 將會在恢復請求體傳輸之前為確認等待
3 秒。

=============================================

第二章 連線管理

套接字工廠:
HTTP 連線內部使用 java.net.Socket 物件來處理資料線上路上的傳輸。它們依賴
SocketFactory 介面來建立,初始化和連線套接字。這會使得 HttpClient 的使用者可以提供在執行時指定套接字初始化程式碼的應用程式。 PlainSocketFactory 是建立和初始化普通的(不加密的)套接字的預設工廠。建立套接字的過程和連線到主機的過程是不成對的,所以套接字在連線操作封鎖時可以被關閉。

PlainSocketFactory sf = PlainSocketFactory.getSocketFactory();
Socket socket = sf.createSocket();
HttpParams params = new BasicHttpParams();
params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT,1000L);
sf.connectSocket(socket, "locahost", 8080, null, -1, params);

安全套接字分層:
LayeredSocketFactory 是 SocketFactory 介面的擴充套件。 分層的套接字工廠可
以建立在已經存在的普通套接字之上的分層套接字。套接字分層主要通過代理來建立安全的套接字。 HttpClient 附帶實現了 SSL/TLS 分層的 SSLSocketFactory。 請注意 HttpClient 不使用任何自定義加密功能。它完全依賴於標準的 Java 密碼學( JCE)和安全套接字( JSEE)擴充套件。
SSL/TLS 的定製
HttpClient 使用 SSLSocketFactory來建立 SSL連線。SSLSocketFactory允許高度定製。
它可以使用 javax.net.ssl.SSLContext 的例項作為引數, 並使用它來建立定製 SSL
連線。
TrustManager easyTrustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
// 哦,這很簡單!
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
//哦,這很簡單!
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(null, new TrustManager[] { easyTrustManager },
null);
SSLSocketFactory sf = new SSLSocketFactory(sslcontext);
SSLSocket socket = (SSLSocket) sf.createSocket();
socket.setEnabledCipherSuites(new String[]
{ "SSL_RSA_WITH_RC4_128_MD5" });
HttpParams params = new BasicHttpParams();
params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT,
1000L);
sf.connectSocket(socket, "locahost", 443, null, -1, params);

每一個預設的 HttpClient 使用 BrowserCompatHostnameVerifier 的實現。如果
需要的話,它可以指定不同的主機名驗證器實現。
SSLSocketFactory sf = new
SSLSocketFactory(SSLContext.getInstance("TLS"));
sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);


協議模式
Scheme 類代表了一個協議