1. 程式人生 > >android中URLConnection和HttpURLConnection

android中URLConnection和HttpURLConnection

HttpURLConnection

適用於HTTP(RFC 2616)的URLConnection,用於在網路上傳送和接受資料。這個類可以用來發送或者接受那些事先不知道長度的流式資料。

可以採用如下方式使用這個類:

1.通過呼叫URL.openConnection()方法,再執行強制型別轉換獲取HttpURLConnection例項。

2.準備請求。一個網路請求的主要組成部分就是URI,請求頭也可能包含憑證、首選內容型別、Session Cookies等資料。

3.請求體是可選的上傳內容,一個HttpURLConnection物件要想攜帶請求體必須設定setDoOutput(true)。通過寫入getOutputStream()返回的流來傳輸資料。

4.讀取響應。響應資料的頭部通常包含有例如資料內容型別、長度、修改日期以及Session Cookies等元資料。響應資料可以通過getInputStream()返回的流來讀取。如果沒有響應資料,這個方法會返回一個空的流。

5.斷開連線。一旦返回的資料讀取完畢,HttpURLConnection應該通過呼叫disconnect()被關閉。斷開連線會釋放連線使用的資源,以使這些資源被關閉或回收。

例如,獲取http://www.android.com/的網頁資料程式碼如下:

1 URL url = new URL("http://www.android.com/");
2    HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
3 try { 4 InputStream in = new BufferedInputStream(urlConnection.getInputStream()); 5 readStream(in); 6 finally { 7 urlConnection.disconnect(); 8 } 9 }

HTTPS安全通訊

呼叫openConnection()時如果URL字首是https可以獲得一個HttpsURLConnection例項,可以重寫預設的HostnameVerifier和SSLSocketFactory。一個應用程式提供的從SSLConext創建出的SSLSocketFactory可以提供一個自定義用於驗證證書鏈的X509TrustManager和一個自定義用於提供終端證書的X509KeyManager。詳細內容會在HttpsURLConnection中介紹。

處理響應

HttpURLConnection至多會支援五次HTTP重定向,能夠跟隨重定向從一個原始伺服器指向另一個伺服器。但是不支援從HTTPS到HTTP的重定向,反之亦然。

如果HTTP響應顯示發生錯誤,getInputStream()會丟擲IOException異常。通過getErrorStream()可以讀取錯誤資訊。頭部資料通常可以通過getHeaderFields()讀取。

傳送資料

要上傳資料到web伺服器,需要通過setDoOutput(true)將connection設定為用於輸出。

為了達到最佳的效能,你應該:

如果資料長度已知,設定setFixedLengthStreamingMode(int)

如果資料長度未知,設定setChunkStramingMode(int)

否則,HttpURLConnection會強制在傳輸資料前將整個請求體緩存於記憶體中,浪費(或有可能耗盡)堆空間並且增大延遲。

上傳資料的示例程式碼如下:

 1 HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
 2    try {
 3      urlConnection.setDoOutput(true);
 4      urlConnection.setChunkedStreamingMode(0);
 5 
 6      OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
 7      writeStream(out);
 8 
 9      InputStream in = new BufferedInputStream(urlConnection.getInputStream());
10      readStream(in);
11     finally {
12      urlConnection.disconnect();
13    }
14  }

 效能

通過本類獲取的輸入和輸出流不會被快取。大多數呼叫時都應該通過BufferedInputStream或BufferedOutputStream來封裝返回的原始流。批量讀取或寫入的呼叫或可忽略快取。

當與伺服器有大量資料傳輸時,應使用流來限制記憶體中同一時間內資料量。除非你需要一次性將所有資料存入記憶體,將其按照一整個流來處理(而不是將資料視為byte或字串陣列來排序)。

為了減少延遲,HttpURLConnection可以在處理多種請求/響應時使用相同的底層Socket。這導致的結果就是HTTP連線的開啟時間可能會比需要的更長。呼叫disconnect()可能將這個socket返回至一個存有已連線Socket的池中。為了避免這種現象,可以在發出任何HTTP請求前將系統屬性http.keepAlive設定為false。http.maxConnections可以用來控制針對每一個伺服器會有多少閒置連線被保持。

預設情況下,HttpURLConnection的這種實現會要求伺服器使用gzip壓縮。所以,雖然getContentLength()能夠返回傳輸的位元數,但你不應依賴這個方法來預計從getInputStream()可以獲得的位元組數。相反地,你應該一直從流中讀取資料直到讀完為止,也就是當read()返回-1時。Gzip壓縮可以在請求頭部的accept encoding出進行設定以禁用:

1 urlConnection.setRequestProperty("Accept-Encoding", "identity");

處理網路登入

有些Wi-Fi網路需要使用者登入才能提供正常服務。此類登入頁面通常通過HTTP重定向實現。你可以通過getURL()來測試你的連線是否被異常重定向。在請求的頭部資料被接收到之前,這個方法是無效的,你可以通過getHeaderFields()或getInputStream()來觸發頭部資料被接收的操作。

下面是一段檢測請求是否被重定向至其他主機的程式碼:

 1 HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
 2    try {
 3      InputStream in = new BufferedInputStream(urlConnection.getInputStream());
 4      if (!url.getHost().equals(urlConnection.getURL().getHost())) {
 5        // we were redirected! Kick the user out to the browser to sign on?
 6      
 7      ...
 8    } finally {
 9      urlConnection.disconnect();
10    }
11  }

HTTP認證

HttpURLConnection支援Http基礎認證。使用Authenticator來設定VM級的認證處理器:

   Authenticator.setDefault(new Authenticator() {
     protected PasswordAuthentication getPasswordAuthentication() {
       return new PasswordAuthentication(username, password.toCharArray());
     
   });
 }

除非與HTTPS搭配使用,這並不是一種安全的使用者認證機制。特別需要注意的是,通過網路傳輸的使用者名稱、密碼、請求資料和響應資料都是未加密的。