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搭配使用,這並不是一種安全的使用者認證機制。特別需要注意的是,通過網路傳輸的使用者名稱、密碼、請求資料和響應資料都是未加密的。