Java中HttpURLConnection使用詳解、總結。


感謝大佬:https://blog.csdn.net/qq_40036754/article/details/102554755

一、前言

  • 實習第二個月了,遇到了一個問題,需求使用Java 的 HttpURLConnection 來轉發請求。需求也給了示例,但是流程不明白,所以再網上查找了很長時間之后,特來總結一番。

  • 3.3中,是關於這次的問題總結,建議大家看一下。

二、HttpURLConnection 介紹

JDK的java.net包中提供了訪問HTTP協議的基本功能的類:HttpURLConnection。

URLConnection是個抽象類,它有兩個直接子類分別是HttpURLConnection和JarURLConnection。另外一個重要的類是URL,通常URL可以通過傳給構造器一個String類型的參數來生成一個指向特定地址的URL實例。

HttpURLConnection是Java的標准類,它繼承自URLConnection,可用於向指定網站發送GET請求、POST請求。它在URLConnection的基礎上提供了如下便捷的方法:

int getResponseCode();        // 獲取服務器的響應代碼。
String getResponseMessage();  // 獲取服務器的響應消息。
String getResponseMethod();   // 獲取發送請求的方法。
void setRequestMethod(String method); // 設置發送請求的方法。

每個 HttpURLConnection 實例都可用於生成單個請求,但是其他實例可以透明地共享連接到 HTTP 服務器的基礎網絡。請求后在 HttpURLConnection 的 InputStream 或 OutputStream 上調用 close() 方法可以釋放與此實例關聯的網絡資源,但對共享的持久連接沒有任何影響。如果在調用 disconnect() 時持久連接空閑,則可能關閉基礎套接字。

三、GET、POST請求

1、GET請求

package com.feng.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 void doGet(String[] args) {
   		HttpURLConnection httpURLConnection = null;
        try {
            // 1. 得到訪問地址的URL
            URL url = new URL(
                    "http://localhost:8080/Servlet/do_login.do?username=test&password=123456");
            // 2. 得到網絡訪問對象java.net.HttpURLConnection
            httpURLConnection = (HttpURLConnection) url.openConnection();
            /* 3. 設置請求參數(過期時間,輸入、輸出流、訪問方式),以流的形式進行連接 */
            // 設置是否向HttpURLConnection輸出
            httpURLConnection.setDoOutput(false);
            // 設置是否從httpUrlConnection讀入
            httpURLConnection.setDoInput(true);
            // 設置請求方式 默認為GET
            httpURLConnection.setRequestMethod("GET");
            // 設置是否使用緩存
            httpURLConnection.setUseCaches(true);
            // 設置此 HttpURLConnection 實例是否應該自動執行 HTTP 重定向
            httpURLConnection.setInstanceFollowRedirects(true);
            // 設置超時時間
            httpURLConnection.setConnectTimeout(3000);
            // 連接
            httpURLConnection.connect();
            // 4. 得到響應狀態碼的返回值 responseCode
            int code = httpURLConnection.getResponseCode();
            // 5. 如果返回值正常,數據在網絡中是以流的形式得到服務端返回的數據
            String msg = "";
            if (code == 200) { // 正常響應
                // 從流中讀取響應信息
                BufferedReader reader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));
                String line = null;
                while ((line = reader.readLine()) != null) { // 循環從流中讀取
                    msg += line + "\n";
                }
                reader.close(); // 關閉流
            }
            // 顯示響應結果
            log.info(msg);
        } catch (IOException e) {
            log.error("轉發出錯,錯誤信息:"+e.getLocalizedMessage()+";"+e.getClass());
        }finally {
            // 6. 斷開連接,釋放資源
            if (null != httpURLConnection){
                try {
                    httpURLConnection.disconnect();
                }catch (Exception e){
                    log.info("httpURLConnection 流關閉異常:"+ e.getLocalizedMessage());
                }
            }
        }
    }
}

2、POST請求

package com.feng.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 void doPost(String[] args) {
    	HttpURLConnection httpURLConnection = null;
        try {
            // 1. 獲取訪問地址URL
            URL url = new URL("http://localhost:8080/Servlet/do_login.do");
            // 2. 創建HttpURLConnection對象
            httpURLConnection = (HttpURLConnection) url.openConnection();
            /* 3. 設置請求參數等 */
            // 請求方式 默認 GET
            httpURLConnection.setRequestMethod("POST");
            // 超時時間
            httpURLConnection.setConnectTimeout(3000);
            // 設置是否輸出
            httpURLConnection.setDoOutput(true);
            // 設置是否讀入
            httpURLConnection.setDoInput(true);
            // 設置是否使用緩存
            httpURLConnection.setUseCaches(false);
            // 設置此 HttpURLConnection 實例是否應該自動執行 HTTP 重定向
            httpURLConnection.setInstanceFollowRedirects(true);
			// 設置請求頭
			httpURLConnection.addRequestProperty("sysId","sysId");
            // 設置使用標准編碼格式編碼參數的名-值對
            httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            // 連接
            httpURLConnection.connect();
            /* 4. 處理輸入輸出 */
            // 寫入參數到請求中
            String params = "username=test&password=123456";
            OutputStream out = httpURLConnection.getOutputStream();
            out.write(params.getBytes());
            // 簡化
            //httpURLConnection.getOutputStream().write(params.getBytes());
            out.flush();
            out.close();
            // 從連接中讀取響應信息
            String msg = "";
            int code = httpURLConnection.getResponseCode();
            if (code == 200) {
                BufferedReader reader = new BufferedReader(
                        new InputStreamReader(httpURLConnection.getInputStream()));
                String line;
                while ((line = reader.readLine()) != null) {
                    msg += line + "\n";
                }
                reader.close();
            }
            // 處理結果
            log.info(msg);
        } catch (IOException e) {
            log.error("轉發出錯,錯誤信息:"+e.getLocalizedMessage()+";"+e.getClass());
        }finally {
            // 5. 斷開連接
            if (null != httpURLConnection){
                try {
                    httpURLConnection.disconnect();
                }catch (Exception e){
                    log.info("httpURLConnection 流關閉異常:"+ e.getLocalizedMessage());
                }
            }
        }
    }
}

3、總結

從網上找資料的時候,發現 connect() 和 flush() 方法有時寫,有時不寫,還沒有理由,特來總結一番。

a、connect()方法調用不調用:

  • 調用connect()只是建立連接,並不會向服務器傳送數據,只要調用getResponseCode(),就不必要調用connect方法(調用也無妨)。

b、是否調用connect方法?

不需要顯示調用connect方法

c、openConnection()方法到底是如何返回URLConnection對象的:

  • openConnection()在你不自己實現網絡協議等網絡相關抽象類和抽象接口的情況下,此方法最終調用的是sun.net.www.protocol.http.Handler類中的方法

d、必須調用getResponseCode()方法 。

  • 安辰試了一下在不調用getResponseCode()方法的時候,無論是否調用connect()方法,請求都是不能成功的,調用connect()方法只是建立連接,並不會向服務器傳遞數據。
  • 只用調用getRespconseCode()方法時,才會向服務器傳遞數據(有博文說是getInputStream()才會向服務器傳遞數據,getResponseCode中會調用getInputStream方法)。
  • 跟着getResponseCode()源碼發現里面調用了getInputStream()方法,在getInputStream()方法中會判斷當前是否連接,如果沒有連接,則調用connect()方法建立連接。

四、小方法解釋

1、flush()

  • flush()意思是把**緩沖區的內容強制的寫出**。 因為操作系統的某些機制,為了防止一直不停地磁盤讀寫,所以有了延遲寫入的概念,(注意不要和frush()刷新混淆了)

  • 主要用在IO中,即清空緩沖區數據,一般在讀寫流(stream)的時候,數據是先被讀到了內存中,再把數據寫到文件中,當你數據讀完的時候不代表你的數據已經寫完了,因為還有一部分有可能會留在內存這個緩沖區中。這時候如果你調用了close()方法關閉了讀寫流,那么這部分數據就會丟失,所以應該在關閉讀寫流之前先flush()。。

  • 為了防止過於頻繁的寫操作 所以Java提供了一個java.io.BufferedOutputStream類 內部持有一個緩沖區 默認不直接將數據寫到硬盤上 而是存到緩沖區中 直到一定條件后觸發(就是調用上面的flushBuffer()了) 也可以強制通過flush()方法提前觸發。

  • 所以當你認為你完成了某一個比較重要的操作的時候 最好進行一次flush 防止數據在內存中丟失。
    多數時候,如果你最后會調用一次close方法,flush方法是可以不使用的,除非你明確的想使數據盡早寫到磁盤或者網絡上。


補充:注意setRequestMethod()中的字符串參數為大寫!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM