不想引入第三方 Jar 時,JDK 內建 HttpURLConnection 完全足夠應付日常 GET/POST 需求。本文封裝一個線程安全、支援超時、自動釋放資源的工具類。
package com.example.http;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Map;
public final class HttpClient {
private HttpClient() {} // 工具類禁止實例化
/** 發送 GET 請求
* @param urlString 完整 URL (含查詢參數)
* @return 回應 Body 字串
*/
public static String get(String urlString) throws IOException {
return request(urlString, "GET", null);
}
/** 發送 POST 表單請求
* @param urlString 目標 URL
* @param params 表單參數 (key=value 格式會自動拼接)
* @return 回應 Body 字串
*/
public static String post(String urlString, Map params) throws IOException {
return request(urlString, "POST", params);
}
/** 核心請求邏輯 */
private static String request(String urlString, String method, Map params) throws IOException {
HttpURLConnection conn = null;
try {
// GET 參數拼接到 URL
String finalUrl = urlString;
if ("GET".equalsIgnoreCase(method) && params != null && !params.isEmpty()) {
finalUrl += (urlString.contains("?") ? "&" : "?") + buildQuery(params);
}
URL url = new URL(finalUrl);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod(method);
conn.setConnectTimeout(5000);
conn.setReadTimeout(10000);
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
conn.setRequestProperty("User-Agent", "Java-HttpClient/1.0");
conn.setRequestProperty("Accept", "application/json, text/plain, */*");
// POST 寫入 Body
if ("POST".equalsIgnoreCase(method) && params != null && !params.isEmpty()) {
conn.setDoOutput(true);
try (OutputStream os = conn.getOutputStream()) {
os.write(buildQuery(params).getBytes(StandardCharsets.UTF_8));
}
}
// 讀取回應
int status = conn.getResponseCode();
InputStream is = (status >= 200 && status < 300) ? conn.getInputStream() : conn.getErrorStream();
if (is == null) throw new IOException("HTTP " + status + " 無回應流");
try (BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) sb.append(line);
return sb.toString();
}
} finally {
if (conn != null) conn.disconnect(); // 釋放連線
}
}
private static String buildQuery(Map params) {
StringBuilder sb = new StringBuilder();
for (Map.Entry e : params.entrySet()) {
if (sb.length() > 0) sb.append('&');
sb.append(e.getKey()).append('=').append(e.getValue());
}
return sb.toString();
}
// ---- 測試主程式 ----
public static void main(String[] args) {
try {
// GET 測試
String getResp = get("https://httpbin.org/get?key=value");
System.out.println("GET 回應:" + getResp);
// POST 測試
Map params = Map.of("username", "admin", "action", "login");
String postResp = post("https://httpbin.org/post", params);
System.out.println("POST 回應:" + postResp);
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 簡單 GET
String html = HttpClient.get("https://api.example.com/users?id=123");
// POST 表單
Map form = new HashMap<>();
form.put("name", "測試");
form.put("email", "test@example.com");
String result = HttpClient.post("https://api.example.com/users", form);
| 問題 | 解決 |
|---|---|
| 中文亂碼 | 請求/回應均指定 StandardCharsets.UTF_8,確保 Server 端也用 UTF-8 |
| HTTPS 憑證錯誤 | 測試環境可安裝信任憑證,或實作信任所有 TrustManager (僅測試) |
| 大檔案上傳 | 改用 multipart/form-data,需手動組裝 Boundary,建議改用 HttpClient/OkHttp |
| 連線洩漏 | 務必在 finally 呼叫 conn.disconnect(),並關閉所有 Stream |
| 超時不生效 | 檢查伺服器端是否長時間不回應,setReadTimeout 控制讀取等待 |