HttpURLConnection與HttpClient比較和使用示例

1. GET請求與POST請求java

HTTP協議是如今Internet上使用得最多、最重要的協議了,愈來愈多的Java應用程序須要直接經過HTTP協議來訪問網絡資源。apache

在介紹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,跨站請求僞造)攻擊。app

通常來講,Get是向服務器索取數據的一種請求,而Post是向服務器提交數據的一種請求。socket

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發送請求、接收響應很簡單,只要以下幾步便可。

  1. 建立HttpClient對象。
  2. 若是須要發送GET請求,建立HttpGet對象;若是須要發送POST請求,建立HttpPost對象。
  3. 若是須要發送請求參數,可調用HttpGet、HttpPost共同的setParams(HttpParams params)方法來添加請求參數;對於HttpPost對象而言,也可調用setEntity(HttpEntity entity)方法來設置請求參數。
  4. 調用HttpClient對象的execute(HttpUriRequest request)發送請求,執行該方法返回一個HttpResponse。
  5. 調用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協議的),即提升了開發的效率,也方便提升代碼的健壯性。

相關文章
相關標籤/搜索