天天看點

如何使用java.net.URLConnection類發起和處理HTTP請求

  • 準備

      首先我們至少要知道URL和charset,這兩個參數是可選的,取決于功能需求。

String url = "http://example.com";
String charset = "UTF-8";  // Or in Java  and later, use the constant: java.nio.charset.StandardCharsets.UTF_8.name()
String param1 = "value1";
String param2 = "value2";
// ...

String query = String.format("param1=%s&param2=%s", 
     URLEncoder.encode(param1, charset), 
     URLEncoder.encode(param2, charset));
           

  參數query必須是name=vale格式的,并且用&符号來連結。你也可以通過URLEncoder.encode()方法來指定參數的字元集。

String的format()方法是很友善的。當我需要使用字元串連接配接操作符 ’ + ’ 兩次以上的時候,我很喜歡用這個方法。
  • 發起一個帶query參數的HTTP GET請求

      這是一個繁瑣的任務,get請求是預設的請求方法。

URLConnection connection = new URL(url + "?" + query).openConnection();
connection.setRequestProperty("Accept-Charset", charset);
InputStream response = connection.getInputStream();
// ...
           

  任何query參數都要跟URL的?後面。請求頭的Accept-Charset屬性用來告訴伺服器用什麼字元集來編碼參數。如果你不想發送任何參數,你可以不加Accept-Charset屬性。如果你不需要加任何請求頭資訊,甚至你可以使用URL.openStream()快捷方法。

InputStream response = new URL(url).openStream();
// ...
           

  如果另一邊是HttpServlet的話,那麼doGet()方法會被調用,然後可以用HttpServletRequest.getParameter()方法來擷取參數。

  

  你可以列印響應體到控制台來測試,就像下面這樣:

try (Scanner scanner = new Scanner(response)) {
    String responseBody = scanner.useDelimiter("\\A").next();
    System.out.println(responseBody);
}
           
  • 發起一個帶query參數的HTTP POST請求

      通過URLConnection.setDoOutput(true)方法來表明我們發起的是一個POST請求。标準的web表單HTTP POST請求體的Content-Type是application/x-www-form-urlencoded類型。

URLConnection connection = new URL(url).openConnection();
connection.setDoOutput(true); // Triggers POST.
connection.setRequestProperty("Accept-Charset", charset);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + charset);

try (OutputStream output = connection.getOutputStream()) {
    output.write(query.getBytes(charset));
}

InputStream response = connection.getInputStream();
// ...
           
注意:不管你什麼時候送出表單,不要忘了把表單中的

<inputtype="hidden">

<input type="submit">

元素以

name=value

的形式加入到query字元串參數中,因為這是在伺服器端确定你觸發的是哪一個按扭的關鍵。

  你也可以将URLConnection 轉換成HttpURLConnection ,并使用HttpURLConnection.setRequestMethod()方法來表明是一個POST請求。但如果你想要擷取輸出流的話,你仍然需要設定URLConnection.setDoOutput(true)。

HttpURLConnection httpConnection = (HttpURLConnection) new URL(url).openConnection();
httpConnection.setRequestMethod("POST");
// ...
           

  另外,如果另一邊是一個HttpServlet,那麼doPost()方法将會被調用,就可以通過HttpServletRequest.getParameter()方法來擷取參數。

  • 關于發起請求

      你可以用URLConnection.connect()方法來發起一個請求,但當你想要擷取關于HTTP response的任何資訊的時候,請求會自動的發起,諸如:通過URLConnection.getInputStream()方法來擷取響應體等等。上面的例子确實如此,是以connect()方法的調用實際上是多餘的。

  • 收集HTTP響應資訊

    ① HTTP response status:

      在這裡你需要一個HttpURLConnection,如果必要轉換它。

  ② HTTP response headers:

for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
    System.out.println(header.getKey() + "=" + header.getValue());
}
           

  ③ HTTP response encoding:

    當Content-Type屬性設定了字元集參數時,響應體很可能是基于文本的,那麼我們将要在伺服器端以指定的字元集來編碼響應體。

String contentType = connection.getHeaderField("Content-Type");
String charset = null;

for (String param : contentType.replace(" ", "").split(";")) {
    if (param.startsWith("charset=")) {
        charset = param.split("=", )[];
        break;
    }
}

if (charset != null) {
    try (BufferedReader reader = new BufferedReader(new InputStreamReader(response, charset))) {
        for (String line; (line = reader.readLine()) != null;) {
            // ... System.out.println(line) ?
        }
    }
} else {
    // It's likely binary content, use InputStream/OutputStream.
}
           

聲明:文章是經論壇回答翻譯而來。