HttpClient學習(一)

序言、HttpUrlConnection和UrlConnection和DefaultHttpClient

1、HTTPUrlConnection通過setRequestMethod()的方法顯示定義請求的方式;而UrlConnection使用setDoOutPut(true)顯示定義爲Post方法,否則默認是Get方式。

2、HttpUrlConnection使用可以通過setCache進行web緩存;而DefaultHttpClient則不能。

3、絕大多數的情況是:某些網頁的訪問,某些資源的訪問需要用戶的權限,而這些權限是需要涉及到Session和Cookie的處理,使用HttpUrlConnection類可以處理,但是較爲繁瑣,實現難度較大。此時,apache組織了一波開源,形成了HttpClient。

4、DefaultHttpClient繼承AbstractHttpClient,AbstractHttpClient實現了HttpClient。

Apache的HttpClient框架學習

一、基礎

1、報文頭部的處理

1.2、報文頭部信息的解析:

1.2.1、使用response.headIterator進行所有報文頭部的解析;

1.2.2、對於單個的header首部的信息,使用HeaderElementIterator類進行解析。HeaderElementIterator it = new BasicHeaderElementIterator(
response.headerIterator("Set-Cookie"));

2、報文實體

HttpEntity類中封裝了可以獲取報文的一些元數據的方法,如:getContentType()等,而這些元數據大部分的情況下,都是放置在報文的header中的。

2.1、低級別資源的釋放

當我們裂解到了需要的資源,並且已經獲取到了需要的信息,那麼經過此鏈接獲取的剩下的信息就已經顯得無足輕重了,並且http連接不會說自動關閉,這樣就會很浪費資源(服務器,網絡資源),我們可以使用HttpUriRequest#abort()進行連接的中斷。

2.2、相應內容的讀取

使用reponse.getEntity()獲取內容實體,InputStream content = entity.getContent();進行資源的獲取,得到一個InputStream的對象; OutputStream os = null;entity.writeTo(os);進行實體的寫入。

實體的包裝和緩存:使用entity = new BufferedHttpEntity(entity);將得到的實體內容進行包裝緩存,以方便多次讀取。

2.3、實體內容的封裝

HttpClient提供了許多公用的數據容器,譬如:StringEntity,ByteArrayEntity等,這些封裝類能夠很好的幫助我們進行實體內容的封裝。

使用ContentProduce和EntityTemplate類進行自定義使用內容的封裝。

ContentProducer contentProducer = new ContentProducer() {
            @Override
            public void writeTo(OutputStream outputStream) throws IOException {
                Writer writer = new OutputStreamWriter(outputStream, "UTF-8");
                writer.write(...);//進行內容的書寫

            }
        };
EntityTemplate entityTemplate=new EntityTemplate(contentProducer);

使用這樣的包裝,我們基本上就能將我們需要的信息按照我們自己希望存儲的形式包裝起來(譬如:json,xml格式的數據),進而和客戶端(希望獲取這樣形式數據的)進行數據通信。

2.4、HTML表單的提交

通常的表單提交,需要將參數進行URL編碼進行提交,我們使用UrlEncodedFormEntity進行參數封裝,該類會進行URL編碼。

2.5、相應控制器的使用

使用ResponseHandler,不需要擔心該連接是否成功還是出現了異常,該處理器直接會將連接的response返回,直接進行操作。
HttpGet httpGet = new HttpGet("www.baidu.com");
ResponseHandler<?> responseHandler=new ResponseHandler<Object>() {
@Override
public Object handleResponse(HttpResponse httpResponse) throws IOException {
return null;
}
};
try {
Object result = defaultHttpClient.execute(httpGet, responseHandler);
} catch (IOException e) {
e.printStackTrace();
}

3、異常的處理

3.1、http的安全運輸機制

http協議只是面向請求/響應的,不涉及到事務操作層次,因爲不會因爲某次請求時報,不斷的進行重新請求,這是不敢想象的:網絡資源會因此很快的消耗。

3.2、冪等性的確定

本身並不能夠提事務機制的http協議。在某些我們希望進行操作某些事務的操作上面,我們希望可以進行某些機制的建立。譬如:get請求失敗後在某些時間段內進行有限次數的重新連接。但是這樣的機制需要冪等性的支撐:重複n次的操作和1次成功的操作所獲得的結果是一致的。

3.3、基於上述的機制的確定,需要進行的“請求重試處理”

需要進行HttpRequestRetryHandler接口的實現

3.4、Http的請求參數

HttpParams params = new BasicHttpParams();
HttpProtocolParamBean paramsBean = new HttpProtocolParamBean(params);
paramsBean.setVersion(HttpVersion.HTTP_1_1);

使用這樣的方式,可以設置基礎的Http的連接參數;

   httpProtocolParamBean.setContentCharset();
   httpProtocolParamBean.setHttpElementCharset();
   httpProtocolParamBean.setUseExpectContinue();
   httpProtocolParamBean.setUserAgent();
   httpProtocolParamBean.setVersion();

3.5、http參數的設置的影響

‘http.protocol.version’:http協議希望有一個版本,如果沒有設置,就默認是:HTTP/1.1;

‘http.protocol.element-charset’:定義了http協議元素的編碼的字符集,默認是US-ASCLL;
‘http.protocol.content-charset’:定義了爲每個內容主體編碼的默認字符集。這個參數期望得到一個java.lang.String類型的值。如果這個參數沒有被設置,那麼就使用ISO-8859-1;
‘http.useragent’:定義了頭部信息User-Agent的內容。這個參數期望得到一個java.lang.String類型的值。如果這個參數沒有被設置,那麼HttpClient將會爲它自動生成一個值。在android中,默認定義的agent是:Mozilla/5.0 (Linux; U; Android %s) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 %sSafari/533.1
‘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.strict-transfer-encoding’:定義了響應頭部信息中是否含有一個非法的Transfer-Encoding,都要拒絕掉;
‘http.protocol.wait-for-continue’:定義了客戶端應該等待100-Continue響應最大的毫秒級時間間隔。這個參數期望得到一個java.lang.Integer類型的值。如果這個參數沒有被設置,那麼HttpClient將會在恢復請求體傳輸之前爲確認等待3秒。

3.6、以上的參數均要在http連接之前進行設置。

二、httpClient中連接的處理

1、影響http鏈接的參數

1.1、http.socket.timeout:套接字的連接超時時間。(0是無限大的超時時間)

1.2、http.tcp.nodelay:默認是TCP_NODELAY。如果設置成TCP_NAGLE算法,表示http希望通過分組發送來降低帶寬,但是這樣做會導致網絡request/response時間變成(因爲分組需要達到發送的要求才會被髮送出去,每個分組需要等待發送的時間。)

1.3、http.socket.buf_size:內部套接字緩衝的大小,如果沒有設置,默認是8192字節的套接字緩存。(1024*8)

1.4、’http.socket.linger’:使用指定的秒數拖延時間來設置SO_LINGER。最大的連接超時值是平臺指定的。值0暗示了這個選項是關閉的。值-1暗示了使用了JRE默認的。這個設置僅僅影響套接字關閉操作。如果這個參數沒有被設置,那麼就假設值爲-1(JRE默認)。

1.5、http.connection.timeout:直接連接建立的毫秒級時間,默認是0,表示永不超時,如果不進行設置,所有的連接將用不用超時。

1.6、http.connection.stalecheck:boolean類型,決定是否使用舊的連接,默認是true,表示在新的連接之前,進行舊的未處理的http連接檢查,如果需要重連,那麼先進行舊的連接的處理。

1.7、還有一些對連接時請求報文的數據進行限制的參數,這些參數可以不用設置,默認不會進行相關的限制。

2、持久性連接:如果每次請求重新建立http鏈路的連接,是相當耗時和耗費資源的

3、套接字工廠

3.1、普通的Http連接:使用PlainSocketFactory獲取套接字工廠實現類;

3.2、加密的Https連接。

4、DefaultHttpclient構造函數中對connectionmanager和httpParams的處理

 public DefaultHttpClient() {
        super((ClientConnectionManager)null, (HttpParams)null);
        throw new RuntimeException("Stub!");
    }

由此可見,apache的Default所構造的httpClient對http基礎參數根本沒有任何處理,超時時間,套接字工廠,重連機制等均需要自己在使用的過程中自己設置。

三、Http狀態管理

原始的Http協議是面向無狀態的,只是一些貫穿了“請求/響應”的會話。但是現在的一些會話中,我們希望能夠保存一些用戶的會話狀態。

3.1、 Cookies

一個基礎的Cookie包括了:(以BasicClientCookie2爲例,這是最新的cookie標準)

1、構造函數:
public BasicClientCookie2(String name, String value) {
super((String)null, (String)null);
throw new RuntimeException(“Stub!”);
}

2、設置版本(version);
3、設置主機(Domain);
4、設置路徑(path)
5、使用CookieStore將一些cookie對象進行存放。

3.2、如何從CookieStore中拿到CookieStore

BasicHttpClient是藉口HttpClient的實現類,實例化的一個BasicHttpclient這個上下文中存放了http連接的相關信息。實際上BasicHttpContext就是一個ConcurrentHashMap。
這是一個獨立用戶(一個客戶端)的處理過程:

HttpClient httpclient = new DefaultHttpClient();
// 創建cookie store的本地實例
CookieStore cookieStore = new BasicCookieStore();
// 創建本地的HTTP內容
HttpContext localContext = new BasicHttpContext();
// 綁定定製的cookie store到本地內容中
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
HttpGet httpget = new HttpGet("http://www.google.com/");
// 作爲參數傳遞本地內容
HttpResponse response = httpclient.execute(httpget, localContext)

這個localContext中會存儲一些具備“特殊信息”的數據,這些數據在execute的過程中會發揮作用(特定的用戶的cookie等~)。

CookieStore有自己的方法,通過

public interface CookieStore {
    void addCookie(Cookie var1);
    List getCookies();
     boolean clearExpired(Date var1);
    void clear();
}

有以上幾種幾種方法對cookieStore中的cookie進行操作(增,刪,獲取)。

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