使用 JDK 內建 HttpURLConnection 實現無第三方依賴的 HTTP 客戶端,支援 GET/POST、查詢參數、請求標頭、回應解析(狀態碼、標頭、主體、編碼、URL 細節),並封裝為 HttpResponse 資料物件,方便後續處理。
sendGet/sendPost 多載,支援參數 Map 與屬性 Map。send(...) 統一處理:GET 參數拼接至 URL、POST 寫入請求主體、設定通用連線屬性(DoOutput、DoInput、UseCaches)。makeContent(...) 讀取回應流、解析編碼、填充 HttpResponse 所有欄位,最後 disconnect() 釋放連線。純 POJO,包含:urlString, protocol, host, port, file, path, query, ref, userInfo, contentEncoding, content, contentType, code, message, method, connectTimeout, readTimeout, contentCollection(逐行內容)。
// 發送核心邏輯
private HttpResponse send(String urlString, String method,
Map<String,String> params, Map<String,String> props) throws IOException {
if ("GET".equalsIgnoreCase(method) && params != null) {
StringBuilder sb = new StringBuilder();
params.forEach((k,v) -> sb.append(sb.length()==0 ? '?' : '&').append(k).append('=').append(v));
urlString += sb;
}
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod(method);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
if (props != null) props.forEach(conn::addRequestProperty);
if ("POST".equalsIgnoreCase(method) && params != null) {
StringBuilder sb = new StringBuilder();
params.forEach((k,v) -> sb.append('&').append(k).append('=').append(v));
try (var os = conn.getOutputStream()) {
os.write(sb.toString().getBytes());
}
}
return makeContent(urlString, conn);
}
// 回應解析
private HttpResponse makeContent(String urlString, HttpURLConnection conn) throws IOException {
HttpResponse resp = new HttpResponse();
try (InputStream in = conn.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in))) {
StringBuilder body = new StringBuilder();
resp.contentCollection = new Vector<>();
String line;
while ((line = br.readLine()) != null) {
resp.contentCollection.add(line);
body.append(line).append("\r\n");
}
String enc = conn.getContentEncoding();
resp.contentEncoding = (enc != null) ? enc : defaultContentEncoding;
resp.content = new String(body.toString().getBytes(), resp.contentEncoding);
}
// 填充 URL 細節、狀態碼、標頭等...
resp.code = conn.getResponseCode();
resp.message = conn.getResponseMessage();
resp.contentType = conn.getContentType();
resp.method = conn.getRequestMethod();
return resp;
}
public class HttpClientDemo {
public static void main(String[] args) {
try {
HttpRequester requester = new HttpRequester();
HttpResponse resp = requester.sendGet("https://www.example.com");
System.out.println("URL: " + resp.getUrlString());
System.out.println("協定: " + resp.getProtocol());
System.out.println("主機: " + resp.getHost());
System.out.println("狀態碼: " + resp.getCode());
System.out.println("內容編碼: " + resp.getContentEncoding());
System.out.println("方法: " + resp.getMethod());
System.out.println("--- 回應主體 ---");
System.out.println(resp.getContent());
} catch (IOException e) {
e.printStackTrace();
}
}
}
| 優點 | 缺點 |
|---|---|
| 零依賴,JDK 內建 | API 繁瑣,需手動管理資源 |
| 完全掌控連線細節 | 無連線池、重試、非同步支援 |
| 適合簡單、偶發請求 | 處理 Cookie、Redirect、壓縮需自行實作 |
建議:生產環境優先使用 Apache HttpClient 5.x、OkHttp 或 JDK 11+ java.net.http.HttpClient(支援 HTTP/2、非同步、WebSocket)。