# Java怎么發起HTTP請求
HTTP請求是現代應用程序開發中最基礎也最重要的功能之一。無論是調用第三方API、獲取網絡數據還是實現微服務間的通信,都需要使用HTTP協議。Java作為企業級開發的主流語言,提供了多種發起HTTP請求的方式。本文將全面介紹Java中發起HTTP請求的各類方法、最佳實踐以及常見問題解決方案。
## 目錄
1. [HTTP協議基礎](#http協議基礎)
2. [Java原生HTTP客戶端](#java原生http客戶端)
- [HttpURLConnection](#httpurlconnection)
- [HttpClient (Java 11+)](#httpclient-java-11)
3. [第三方HTTP客戶端庫](#第三方http客戶端庫)
- [Apache HttpClient](#apache-httpclient)
- [OkHttp](#okhttp)
- [RestTemplate](#resttemplate)
- [WebClient](#webclient)
4. [HTTP請求方法詳解](#http請求方法詳解)
- [GET請求](#get請求)
- [POST請求](#post請求)
- [PUT/DELETE請求](#putdelete請求)
5. [請求頭與參數處理](#請求頭與參數處理)
6. [響應處理](#響應處理)
7. [異步HTTP請求](#異步http請求)
8. [HTTPS與證書處理](#https與證書處理)
9. [性能優化](#性能優化)
10. [常見問題與解決方案](#常見問題與解決方案)
11. [總結與建議](#總結與建議)
## HTTP協議基礎
HTTP(HyperText Transfer Protocol)是應用層協議,用于分布式、協作式和超媒體信息系統的應用層協議。HTTP是無狀態協議,意味著服務器不會在兩個請求之間保留任何數據(狀態)。
主要特點:
- 基于請求/響應模型
- 簡單快速
- 靈活(可以傳輸任意類型數據)
- 無連接(每次連接只處理一個請求)
- 無狀態
HTTP請求由以下部分組成:
1. 請求行(方法、URL、協議版本)
2. 請求頭(Header)
3. 空行
4. 請求體(Body)
## Java原生HTTP客戶端
### HttpURLConnection
`HttpURLConnection`是Java最基礎的HTTP客戶端,存在于`java.net`包中,自JDK1.1就已存在。
```java
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class HttpURLConnectionExample {
public static void main(String[] args) throws Exception {
URL url = new URL("https://example.com/api");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 設置請求方法
connection.setRequestMethod("GET");
// 設置請求頭
connection.setRequestProperty("User-Agent", "Java HTTP Client");
connection.setRequestProperty("Accept", "application/json");
// 獲取響應碼
int responseCode = connection.getResponseCode();
System.out.println("Response Code: " + responseCode);
// 讀取響應內容
try (BufferedReader in = new BufferedReader(
new InputStreamReader(connection.getInputStream()))) {
String line;
StringBuilder response = new StringBuilder();
while ((line = in.readLine()) != null) {
response.append(line);
}
System.out.println("Response: " + response.toString());
}
// 關閉連接
connection.disconnect();
}
}
優點: - JDK內置,無需額外依賴 - 簡單請求場景下使用方便
缺點: - API設計較為底層,使用繁瑣 - 缺乏連接池管理 - 錯誤處理不夠友好 - 不支持HTTP/2
Java 11引入了新的HttpClient
,位于java.net.http
包中,支持HTTP/2和WebSocket,提供了同步和異步兩種調用方式。
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class HttpClientExample {
public static void main(String[] args) throws Exception {
// 創建HttpClient實例
HttpClient client = HttpClient.newHttpClient();
// 構建請求
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://example.com/api"))
.header("Content-Type", "application/json")
.GET()
.build();
// 發送同步請求
HttpResponse<String> response = client.send(
request, HttpResponse.BodyHandlers.ofString());
System.out.println("Status code: " + response.statusCode());
System.out.println("Response body: " + response.body());
// 異步請求示例
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println)
.join();
}
}
優點: - 現代API設計,使用流暢 - 支持HTTP/2 - 內置異步支持 - 更好的性能
缺點: - 需要Java 11+環境 - 某些高級功能仍需第三方庫
Apache HttpClient是功能最全面的Java HTTP客戶端之一,提供了豐富的功能和配置選項。
Maven依賴:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
使用示例:
import org.apache.http.HttpEntity;
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.HttpClients;
import org.apache.http.util.EntityUtils;
public class ApacheHttpClientExample {
public static void main(String[] args) throws Exception {
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpGet request = new HttpGet("https://example.com/api");
// 設置請求頭
request.addHeader("User-Agent", "Apache HttpClient");
try (CloseableHttpResponse response = httpClient.execute(request)) {
// 獲取響應狀態
System.out.println(response.getStatusLine().toString());
// 獲取響應內容
HttpEntity entity = response.getEntity();
if (entity != null) {
String result = EntityUtils.toString(entity);
System.out.println(result);
}
}
}
}
}
特點: - 成熟的HTTP客戶端實現 - 支持連接池管理 - 支持多種認證機制 - 支持HTTPS - 支持自定義攔截器
OkHttp是由Square公司開發的現代HTTP客戶端,Android開發中廣泛使用,但也適用于Java應用。
Maven依賴:
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.3</version>
</dependency>
使用示例:
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class OkHttpExample {
public static void main(String[] args) throws Exception {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://example.com/api")
.addHeader("Accept", "application/json")
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new RuntimeException("Unexpected code " + response);
}
System.out.println(response.body().string());
}
}
}
特點: - 簡潔的API設計 - 自動GZIP壓縮 - 響應緩存 - 連接池復用 - 支持HTTP/2
RestTemplate是Spring框架提供的HTTP客戶端,雖然已被標記為過時(推薦使用WebClient),但在許多項目中仍有使用。
import org.springframework.web.client.RestTemplate;
public class RestTemplateExample {
public static void main(String[] args) {
RestTemplate restTemplate = new RestTemplate();
String url = "https://example.com/api";
// GET請求
String response = restTemplate.getForObject(url, String.class);
System.out.println(response);
// POST請求
// String requestBody = "{\"key\":\"value\"}";
// String postResponse = restTemplate.postForObject(url, requestBody, String.class);
}
}
特點: - 與Spring生態集成良好 - 自動對象映射(JSON/XML) - 支持OAuth等安全機制
WebClient是Spring 5引入的響應式HTTP客戶端,支持異步和非阻塞IO。
Maven依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
使用示例:
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
public class WebClientExample {
public static void main(String[] args) {
WebClient client = WebClient.create("https://example.com");
Mono<String> response = client.get()
.uri("/api")
.retrieve()
.bodyToMono(String.class);
// 阻塞獲取結果(實際應用中通常不阻塞)
System.out.println(response.block());
}
}
特點: - 響應式編程模型 - 支持HTTP/2 - 非阻塞IO - 流式處理 - 與Spring生態深度集成
GET是最常見的HTTP方法,用于獲取資源。
// 使用HttpURLConnection
URL url = new URL("https://example.com/api?param1=value1¶m2=value2");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
// 使用HttpClient
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://example.com/api?param1=value1¶m2=value2"))
.GET()
.build();
POST用于提交數據到服務器。
// 使用HttpURLConnection
URL url = new URL("https://example.com/api");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
String postData = "param1=value1¶m2=value2";
try (OutputStream os = connection.getOutputStream()) {
byte[] input = postData.getBytes("utf-8");
os.write(input, 0, input.length);
}
// 使用HttpClient
String requestBody = "{\"key\":\"value\"}";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://example.com/api"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
PUT用于更新資源,DELETE用于刪除資源。
// PUT請求示例
HttpRequest putRequest = HttpRequest.newBuilder()
.uri(URI.create("https://example.com/api/123"))
.header("Content-Type", "application/json")
.PUT(HttpRequest.BodyPublishers.ofString("{\"name\":\"new value\"}"))
.build();
// DELETE請求示例
HttpRequest deleteRequest = HttpRequest.newBuilder()
.uri(URI.create("https://example.com/api/123"))
.DELETE()
.build();
// HttpURLConnection
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Authorization", "Bearer token");
// HttpClient
HttpRequest request = HttpRequest.newBuilder()
.header("Content-Type", "application/json")
.header("Authorization", "Bearer token")
.build();
// 手動構建查詢字符串
String query = "param1=" + URLEncoder.encode("value1", StandardCharsets.UTF_8) +
"?m2=" + URLEncoder.encode("value2", StandardCharsets.UTF_8);
// 使用URIBuilder (Apache HttpClient)
URI uri = new URIBuilder("https://example.com/api")
.addParameter("param1", "value1")
.addParameter("param2", "value2")
.build();
// 使用URL編碼表單
String form = "username=" + URLEncoder.encode("user", "UTF-8") +
"&password=" + URLEncoder.encode("pass", "UTF-8");
// 使用MultiValueMap (Spring)
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add("username", "user");
formData.add("password", "pass");
// HttpURLConnection
int status = connection.getResponseCode();
if (status == HttpURLConnection.HTTP_OK) {
// 處理成功響應
} else {
// 處理錯誤
}
// HttpClient
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
System.out.println(response.body());
} else {
System.out.println("Error: " + response.statusCode());
}
// 使用Jackson
ObjectMapper mapper = new ObjectMapper();
MyObject obj = mapper.readValue(response.body(), MyObject.class);
// 使用Gson
Gson gson = new Gson();
MyObject obj = gson.fromJson(response.body(), MyObject.class);
// 獲取字節數組
byte[] bytes = response.body().getBytes();
// 保存為文件
try (FileOutputStream fos = new FileOutputStream("file.png")) {
fos.write(bytes);
}
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://example.com/api"))
.build();
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println)
.exceptionally(e -> {
System.err.println("Error: " + e.getMessage());
return null;
});
// 主線程繼續執行其他任務
System.out.println("Request sent asynchronously");
WebClient client = WebClient.create("https://example.com");
client.get()
.uri("/api")
.retrieve()
.bodyToMono(String.class)
.subscribe(
response -> System.out.println("Response: " + response),
error -> System.err.println("Error: " + error.getMessage())
);
// 創建信任所有證書的HttpClient
HttpClient client = HttpClient.newBuilder()
.sslContext(createUnsafeSSLContext())
.build();
private static SSLContext createUnsafeSSLContext() throws Exception {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) {}
public void checkServerTrusted(X509Certificate[] chain, String authType) {}
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
}
};
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new SecureRandom());
return sslContext;
}
// 加載自定義信任庫
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
try (InputStream is = new FileInputStream("truststore.jks")) {
keyStore.load(is, "password".toCharArray());
}
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
HttpClient client = HttpClient.newBuilder()
.sslContext(sslContext)
.build();
// Apache HttpClient連接池配置
PoolingHttpClientConnectionManager connectionManager =
new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(200); // 最大連接數
connectionManager.setDefaultMaxPerRoute(20); // 每個路由最大連接數
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(connectionManager)
.build();
// HttpClient超時設置
HttpClient client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.build();
// Apache HttpClient超時設置
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(5000)
.setSocketTimeout(5000)
.build();
CloseableHttpClient httpClient = HttpClients.custom()
.setDefaultRequestConfig(config)
.build();
// OkHttp緩存配置
int cacheSize = 10 * 1024 * 1024; // 10MB
Cache cache = new Cache(new File("http-cache"), cacheSize);
OkHttpClient client = new OkHttpClient.Builder()
.cache(cache)
.build();
問題表現:java.net.ConnectException: Connection timed out
解決方案: - 檢查網絡連接 - 增加連接超時時間 - 檢查目標服務器是否可達
// 設置連接超時
HttpClient client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(30))
.build();
問題表現:javax.net.ssl.SSLHandshakeException
解決方案: - 導入正確的證書 - 開發環境可以臨時禁用證書驗證(不推薦生產環境使用)
問題表現:com.fasterxml.jackson.core.JsonParseException
解決方案: - 檢查響應內容是否符合預期格式 - 添加錯誤處理邏輯
try {
ObjectMapper mapper = new ObjectMapper();
MyObject obj = mapper.readValue(response, MyObject.class);
} catch (JsonProcessingException e) {
System.err.println("Failed to parse JSON: " + e.getMessage());
// 處理錯誤情況
}
問題表現:應用逐漸變慢,最終耗盡連接資源
解決方案: - 確保所有資源都被正確關閉 -
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。