HttpURLConnection與HttpClient隨筆
目前在工作中遇到的需要各種對接接口的工作,需要用到HTTP的知識,工作完成後想要做一些筆記,本來知識打算把自己寫的代碼粘貼上來就好了,但是偶然發現一篇博文對這些知識的總結非常到位,自認無法寫的這麽好,所以就直接拷貝了,但是自己的代碼也還是要貼上來的,畢竟將來還是看自己的代碼有印象。
這篇博文的地址:http://blog.csdn.net/zhliro/article/details/46877519
(一)HttpURLConnection與HttpClient淺析
1. GET請求與POST請求
HTTP協議是現在Internet上使用得最多、最重要的協議了,越來越多的Java應用程序需要直接通過HTTP協議來訪問網絡資源。
在介紹HttpURLConnection前,我們還是再來說一下URL請求最常用的兩種方式:GET請求與POST請求。
GET請求的數據會附在URL之後(就是把數據放置在HTTP協議頭中),以?分割URL和傳輸數據,參數之間以&相連,如:http://localhost:8080/test.do?name=test&password=123456。
GET請求發送的參數如果數據是英文字母或數字,則按原樣發送,如果是空格,則轉換為+,如果是中文或其他字符,則直接把字符串用BASE64加密,得出如 %E4%BD%A0%E5%A5%BD
這類似的字符串,其中%XX中的XX為該符號以16進制表示的ASCII。
POST請求的參數不是放在URL字符串裏面,而是放在HTTP請求的正文內,請求的參數被封裝起來以流的形式發送給服務端。
對於GET方式提交數據的大小,HTTP協議並沒有硬性限制,但某些瀏覽器及服務器會對它進行限制,如IE對URL長度的限制是2083字節(2K+35)。理論上POST也沒有限制,可傳較大量的數據。
POST的安全性要比GET的安全性高。比如:通過GET提交數據,用戶名和密碼將明文出現在URL上,因為登錄頁面有可能被瀏覽器緩存,如果其他人查看瀏覽器的歷史紀錄,那麽別人就可以拿到你的賬號和密碼了,除此之外,使用GET提交數據還可能會造成Cross-site request forgery(CSRF,跨站請求偽造)攻擊。
一般來說,Get是向服務器索取數據的一種請求,而Post是向服務器提交數據的一種請求。
2. HttpURLConnection簡介
在JDK的java.net包中已經提供了訪問HTTP協議的基本功能的類:HttpURLConnection。
HttpURLConnection是Java的標準類,它繼承自URLConnection,可用於向指定網站發送GET請求、POST請求。它在URLConnection的基礎上提供了如下便捷的方法:
int getResponseCode(); // 獲取服務器的響應代碼。
String getResponseMessage(); // 獲取服務器的響應消息。
String getResponseMethod(); // 獲取發送請求的方法。
void setRequestMethod(String method); // 設置發送請求的方法。
3. HttpURLConnection的使用
3.1 使用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請求示例
*
* @author 小明
*
*/
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();
}
}
}
3.2 使用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請求示例
*
* @author 小明
*
*/
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);
// 設置是否輸出
connection.setDoOutput(true);
// 設置是否讀入
connection.setDoInput(true);
// 設置是否使用緩存
connection.setUseCaches(false);
// 設置此 HttpURLConnection 實例是否應該自動執行 HTTP 重定向
connection.setInstanceFollowRedirects(true);
// 設置使用標準編碼格式編碼參數的名-值對
connection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
// 連接
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();
}
}
}
3.3 說明
- HttpURLConnection對象不能直接構造,需要通過URL類中的openConnection()方法來獲得。
- HttpURLConnection的connect()函數,實際上只是建立了一個與服務器的TCP連接,並沒有實際發送HTTP請求。HTTP請求實際上直到我們獲取服務器響應數據(如調用getInputStream()、getResponseCode()等方法)時才正式發送出去。
- 對HttpURLConnection對象的配置都需要在connect()方法執行之前完成。
- HttpURLConnection是基於HTTP協議的,其底層通過socket通信實現。如果不設置超時(timeout),在網絡異常的情況下,可能會導致程序僵死而不繼續往下執行。
- HTTP正文的內容是通過OutputStream流寫入的, 向流中寫入的數據不會立即發送到網絡,而是存在於內存緩沖區中,待流關閉時,根據寫入的內容生成HTTP正文。
- 調用getInputStream()方法時,返回一個輸入流,用於從中讀取服務器對於HTTP請求的返回信息。
- 我們可以使用HttpURLConnection.connect()方法手動的發送一個HTTP請求,但是如果要獲取HTTP響應的時候,請求就會自動的發起,比如我們使用HttpURLConnection.getInputStream()方法的時候,所以完全沒有必要調用connect()方法。
4. 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連接。
5. HttpClient的使用
使用HttpClient發送請求、接收響應很簡單,只要如下幾步即可。
- 創建HttpClient對象。
- 如果需要發送GET請求,創建HttpGet對象;如果需要發送POST請求,創建HttpPost對象。
- 如果需要發送請求參數,可調用HttpGet、HttpPost共同的setParams(HttpParams params)方法來添加請求參數;對於HttpPost對象而言,也可調用setEntity(HttpEntity entity)方法來設置請求參數。
- 調用HttpClient對象的execute(HttpUriRequest request)發送請求,執行該方法返回一個HttpResponse。
- 調用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可獲取服務器的響應頭;調用HttpResponse的getEntity()方法可獲取HttpEntity對象,該對象包裝了服務器的響應內容。程序可通過該對象獲取服務器的響應內容。
5.1 使用GET方式訪問HTTP
package com.qf.client;
import java.io.IOException;
import org.apache.http.HttpEntity;
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.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
/**
* GET請求示例
*
* @author 小明
*
*/
public class GetDemo {
public static void main(String[] args) {
// 1. 創建HttpClient對象
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
// 2. 創建HttpGet對象
HttpGet httpGet = new HttpGet(
"http://localhost:8080/Servlet/do_login.do?username=test&password=123456");
CloseableHttpResponse response = null;
try {
// 3. 執行GET請求
response = httpClient.execute(httpGet);
System.out.println(response.getStatusLine());
// 4. 獲取響應實體
HttpEntity entity = response.getEntity();
// 5. 處理響應實體
if (entity != null) {
System.out.println("長度:" + entity.getContentLength());
System.out.println("內容:" + EntityUtils.toString(entity));
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 6. 釋放資源
try {
response.close();
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5.2 使用POST方式訪問HTTP
package com.qf.client;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
/**
* POST請求測試
*
* @author 小明
*
*/
public class PostDemo {
public static void main(String[] args) {
// 1. 創建HttpClient對象
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
// 2. 創建HttpPost對象
HttpPost post = new HttpPost(
"http://localhost:8080/Servlet/do_login.do");
// 3. 設置POST請求傳遞參數
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("username", "test"));
params.add(new BasicNameValuePair("password", "12356"));
try {
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params);
post.setEntity(entity);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
// 4. 執行請求並處理響應
try {
CloseableHttpResponse response = httpClient.execute(post);
HttpEntity entity = response.getEntity();
if (entity != null){
System.out.println("響應內容:");
System.out.println(EntityUtils.toString(entity));
}
response.close();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 釋放資源
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5.3 說明
HttpClient相比傳統JDK自帶的URLConnection,增加了易用性和靈活性,它不僅使客戶端發送HTTP請求變得容易,而且也方便了開發人員測試接口(基於Http協議的),即提高了開發的效率,也方便提高代碼的健壯性。
二、以上都是那篇博文的內容(防止被作者刪掉後找不到了)
接下來就是自己的部分代碼了,只用到了HttpURLConnection的GET請求,和HttpClient的post請求:
(1)HttpURLConnection
/** * 獲取固定資產待辦列表 */ public List<WorkItem> GetOwnerWorkItemList(){ com.ccidit.platform.sdk.UserVO curUser = UserContext.getCurrentContext().getUserSession().getUser(); List<WorkItem> OwnerWorkItemList = new ArrayList<WorkItem>(); String requestUrl = "http://172.16.80.65:8801/WorkItem/GetOwnerWorkItemList?param="+curUser.getCname(); HttpURLConnection con = null; String result = null; try { URL url = new URL(requestUrl); con = (HttpURLConnection) url.openConnection(); con.setRequestMethod("GET"); con.setConnectTimeout(10000); con.setReadTimeout(2000); con.setDoOutput(false); // post改為true con.setDoInput(true); con.setUseCaches(false); con.setRequestProperty("Content-Type", "text/plain"); con.connect(); int code = con.getResponseCode(); if (code == 200) { // 讀取返回內容 StringBuffer buffer = new StringBuffer(); BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8")); String temp; while ((temp = br.readLine()) != null) { buffer.append(temp); buffer.append("\n"); } result = buffer.toString().trim(); result = result.substring(0, result.length()-1); result = result.substring(1); result = StringEscapeUtils.unescapeJava(result); JSONObject jsonObject = new JSONObject(result); WorkItem workitem = new WorkItem(); workitem.setCount(jsonObject.get("Count").toString()); workitem.setURL(jsonObject.get("URL").toString()); OwnerWorkItemList.add(workitem); } else { BufferedReader br = new BufferedReader(new InputStreamReader( con.getErrorStream(), "UTF-8")); StringBuffer buffer = new StringBuffer(); String temp; while ((temp = br.readLine()) != null) { buffer.append(temp); buffer.append("\n"); } } } catch (Exception e) { } finally { con.disconnect(); } return OwnerWorkItemList; }
(2)HttpClient
JSONObject obj = new JSONObject(); obj.put("toUser",""); obj.put("toParty", ""); obj.put("toTag", ""); obj.put("timeOut", "30"); JSONArray array = new JSONArray(); JSONObject obj1 = new JSONObject(); obj1.put("content",article.getContent()); obj1.put("description", article.getDescription()); obj1.put("picUrl", "http://img.nbdpx.com/upload/2/e2/2e24c2af1bd9b861871a9423d6199fee.jpg"); obj1.put("title",article.getTitle()); array.put(obj1); obj.put("articles", array); this.sendHttpPost(obj); public void sendHttpPost(JSONObject obj){ String jsonString = getImgStr(obj.toString()); HttpclientUtil.httpPostclientUtil(jsonString.toString(), "http://sp.ccidindustrymap.com/_vti_bin/WXMessageService.svc/SendNews"); }
package com.ccidit.features.xtoaMgt.util; import java.nio.charset.Charset; import java.util.UUID; import org.apache.commons.httpclient.HttpStatus; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.CoreConnectionPNames; import org.apache.http.util.EntityUtils; import net.sf.json.JSONObject; public class HttpclientUtil { public static String httpPostclientUtil(String jsonObj,String url){ boolean isSuccess = false; String result = ""; HttpPost post = null; try { HttpClient httpClient = new DefaultHttpClient(); // 設置超時時間 httpClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 2000); httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 2000); post = new HttpPost(url); // 構造消息頭 post.setHeader("Content-type", "application/json; charset=utf-8"); post.setHeader("Connection", "Close"); String sessionId = getSessionId(); post.setHeader("SessionId", sessionId); // 構建消息實體 StringEntity entity = new StringEntity(jsonObj, Charset.forName("UTF-8")); entity.setContentEncoding("UTF-8"); // 發送Json格式的數據請求 entity.setContentType("application/json"); post.setEntity(entity); HttpResponse response = httpClient.execute(post); // 檢驗返回碼 int statusCode = response.getStatusLine().getStatusCode(); if(statusCode==200){ //5.獲取HttpEntity消息載體對象 可以接收和發送消息 HttpEntity entity1=response.getEntity(); //EntityUtils中的toString()方法轉換服務器的響應數據 result=EntityUtils.toString(entity1, "utf-8"); //System.out.println("服務器的響應是:"+str); // //6.從消息載體對象中獲取操作的讀取流對象 // InputStream input=entity.getContent(); // BufferedReader br=new BufferedReader(new InputStreamReader(input)); // String str=br.readLine(); // String result=new String(str.getBytes("gbk"), "utf-8"); // System.out.println("服務器的響應是:"+result); // br.close(); // input.close(); }else{ JSONObject obj = new JSONObject(); obj.put("result", "failure"); result=obj.toString(); } } catch (Exception e) { e.printStackTrace(); isSuccess = false; }finally{ if(post != null){ try { post.releaseConnection(); Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } return result; } // 構建唯一會話Id public static String getSessionId(){ UUID uuid = UUID.randomUUID(); String str = uuid.toString(); return str.substring(0, 8) + str.substring(9, 13) + str.substring(14, 18) + str.substring(19, 23) + str.substring(24); } }
OK,學然後知不足,教然後知困。知不足,然後能自反也;知困,然後能自強也。
HttpURLConnection與HttpClient隨筆