HttpURLConnection簡介
在JDK的 java.net 包中已經提供了訪問HTTP協議的基本功能的類:HttpURLConnection。
HttpURLConnection是Java的標准類,它繼承自URLConnection,可用於向指定網站發送GET請求、POST請求。
它在URLConnection的基礎上提供了如下便捷的方法:
int getResponseCode(); // 獲取服務器的響應代碼。 String getResponseMessage(); // 獲取服務器的響應消息。 String getResponseMethod(); // 獲取發送請求的方法。 void setRequestMethod(String method); // 設置發送請求的方法。
HttpURLConnection使用
- 使用GET方式訪問HTTP
package com.qf.demo; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; /** * GET請求示例*/ public class GetDemo { public static void main(String[] args) { try { // 1. 得到訪問地址的URL URL url = new URL("http://localhost:8080/Servlet/do_login.do?username=test&password=123456"); // 2. 得到網絡訪問對象java.net.HttpURLConnection HttpURLConnection connection = (HttpURLConnection) url.openConnection(); /* 3. 設置請求參數(過期時間,輸入、輸出流、訪問方式),以流的形式進行連接 */ // 設置是否向HttpURLConnection輸出 connection.setDoOutput(false); // 設置是否從HttpUrlConnection讀入 connection.setDoInput(true); // 設置請求方式 connection.setRequestMethod("GET"); // 設置是否使用緩存 connection.setUseCaches(true); // 設置此 HttpURLConnection 實例是否應該自動執行 HTTP 重定向 connection.setInstanceFollowRedirects(true); // 設置超時時間 connection.setConnectTimeout(3000); // 連接 connection.connect(); // 4. 得到響應狀態碼的返回值 responseCode int code = connection.getResponseCode(); // 5. 如果返回值正常,數據在網絡中是以流的形式得到服務端返回的數據 String msg = ""; if (code == 200) { // 正常響應 // 從流中讀取響應信息 BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); String line = null; while ((line = reader.readLine()) != null) { // 循環從流中讀取 msg += line + "\n"; } reader.close(); // 關閉流 } // 6. 斷開連接,釋放資源 connection.disconnect(); // 顯示響應結果 System.out.println(msg); } catch (IOException e) { e.printStackTrace(); } } }
- 使用POST方式訪問HTTP
package com.qf.demo; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; /** * POST請求示例*/ public class PostDemo { public static void main(String[] args) { try { // 1. 獲取訪問地址URL URL url = new URL("http://localhost:8080/Servlet/do_login.do"); // 2. 創建HttpURLConnection對象 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); /* 3. 設置請求參數等 */ // 請求方式 connection.setRequestMethod("POST"); // 設置連接超時時間 connection.setConnectTimeout(3000);
// 設置是否向 HttpUrlConnection 輸出,對於post請求,參數要放在 http 正文內,因此需要設為true,默認為false。 connection.setDoOutput(true); // 設置是否從 HttpUrlConnection讀入,默認為true connection.setDoInput(true); // 設置是否使用緩存 connection.setUseCaches(false); // 設置此 HttpURLConnection 實例是否應該自動執行 HTTP 重定向 connection.setInstanceFollowRedirects(true); // 設置使用標准編碼格式編碼參數的名-值對 connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
// 添加 HTTP HEAD 中的一些參數。
// JDK8中,HttpURLConnection默認開啟Keep-Alive // connection.setRequestProperty("Connection", "Keep-Alive"); // 連接 connection.connect(); /* 4. 處理輸入輸出 */ // 寫入參數到請求中 String params = "username=test&password=123456"; OutputStream out = connection.getOutputStream(); out.write(params.getBytes()); out.flush(); out.close(); // 從連接中讀取響應信息 String msg = ""; int code = connection.getResponseCode(); if (code == 200) { BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); String line; while ((line = reader.readLine()) != null) { msg += line + "\n"; } reader.close(); } // 5. 斷開連接 connection.disconnect(); // 處理結果 System.out.println(msg); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
- Servlet服務端開發
HttpURLConnection說明
- HttpURLConnection對象不能直接構造,需要通過URL類中的openConnection()方法來獲得。
- 對HttpURLConnection對象的配置都需要在connect()方法執行之前完成,因為connect()會根據HttpURLConnection對象的配置值生成HTTP頭部信息。
- HttpURLConnection的connect()函數,實際上只是建立了一個與服務器的TCP連接,並沒有實際發送HTTP請求。HTTP請求實際上直到我們獲取服務器響應數據(如調用getInputStream()、getResponseCode()等方法)時才正式發送出去。
- HttpURLConnection是基於HTTP協議的,其底層通過socket通信實現。如果不設置超時(timeout),在網絡異常的情況下,可能會導致程序僵死而不繼續往下執行。
- HTTP正文的內容是通過OutputStream流寫入的, 向流中寫入的數據不會立即發送到網絡,而是存在於內存緩沖區中,待流關閉時,根據寫入的內容生成HTTP正文。
- 調用getInputStream()方法時,返回一個輸入流,用於從中讀取服務器對於HTTP請求的返回信息。
- 我們可以使用HttpURLConnection.connect()方法手動的發送一個HTTP請求,但是如果要獲取HTTP響應的時候,請求就會自動的發起,比如我們使用HttpURLConnection.getInputStream()方法的時候,所以完全沒有必要調用connect()方法。
HttpURLConnection長連接(Keep-Alive)
JDK8自帶的HttpURLConnection,默認啟用keepAlive,支持HTTP / 1.1和HTTP / 1.0持久連接,
使用后的HttpURLConnection會放入緩存中供以后的同host:port的請求重用,底層的socket在keepAlive超時之前不會關閉。
HttpURLConnection受以下system properties控制:
http.keepAlive=<boolean>(默認值:true)
,是否啟用keepAlive,如果設置為false,則HttpURLConnection不會緩存,使用完后會關閉socket連接。http.maxConnections=<int>(默認值:5)
,每個目標host緩存socket連接的最大數。
說明:
- 如果在HttpURLConnection的header中加入Connection: close,則此連接不會啟用keepAlive
- 想要啟用keepAlive,程序請求完畢后,必須調用HttpURLConnection.getInputStream().close()
(表示歸還長連接給緩存,以供下次同host:port的請求重用底層socket連接)
,而不能調用HttpURLConnection.disconnect()(表示關閉底層socket連接,不會啟用keepAlive)
- keepAliveTimeout首先從http response header中獲取,如果沒有取到,則默認為5秒,sun.net.www.http.KeepAliveCache.java中有一個線程,每5秒執行一次,檢查緩存的連接的空閑時間是否超過keepAliveTimeout,如果超過則關閉連接。從KeepAliveCache中獲取緩存的連接時也會檢查獲取到的連接的空閑時間是否超過keepAliveTimeout,如果超過則關閉連接,並且獲取下一個連接,再執行以上檢查,直達獲取到空閑時間在keepAliveTimeout以內的緩存連接為此。
HttpURLConnection關閉
本身要 HttpURLConnection 是很簡單的,調用 connection.disconnect()
就可以了。
這里是想說明一下,是否需要關閉,應該根據實際需要來:
- 當 HttpURLConnection 是 "Connection: close " 模式,那么關閉 inputStream 后就會自動斷開連接。
- 當 HttpURLConnection 是 "Connection: Keep-Alive" 模式,那么關閉 inputStream 后,並不會斷開底層的 Socket 連接。這樣的好處,是當需要連接到同一服務器地址時,可以復用該 Socket。這時如果要求斷開連接,就可以調用
connection.disconnect()
了。
當然,HttpURLConnection 連接到底是不是 Keep-Alive 模式,除了 HttpURLConnection 請求設置為 Keep-Alive 外 (http 1.0中默認是關閉的,http 1.1中默認啟用Keep-Alive),也需要服務器支持 Keep-Alive,才可以真正建立 Keep-Alive 連接。
與HttpClient的區別
在一般情況下,如果只是需要向Web站點的某個簡單頁面提交請求並獲取服務器響應,HttpURLConnection完全可以勝任。但在絕大部分情況下,
Web站點的網頁可能沒這么簡單,這些頁面並不是通過一個簡單的URL就可訪問的,可能需要用戶登錄而且具有相應的權限才可訪問該頁面。
在這種情況下,就需要涉及Session、Cookie的處理了,如果打算使用HttpURLConnection來處理這些細節,當然也是可能實現的,只是處理起來難度就大了。
為了更好地處理向Web站點請求,包括處理Session、Cookie等細節問題,Apache開源組織提供了一個HttpClient項目,看它的名稱就知道,
它是一個簡單的HTTP客戶端(並不是瀏覽器),可以用於發送HTTP請求,接收HTTP響應。但不會緩存服務器的響應,
不能執行HTML頁面中嵌入的Javascript代碼;也不會對頁面內容進行任何解析、處理。
簡單來說,HttpClient就是一個增強版的HttpURLConnection,HttpURLConnection可以做的事情HttpClient全部可以做;
HttpURLConnection沒有提供的有些功能,HttpClient也提供了,但它只是關注於如何發送請求、接收響應,以及管理HTTP連接。
- https://www.jianshu.com/p/cfefdc4e062e
- http://www.itersblog.com/archives/3.html