HTTP Client API
JDK 11 之前,如果你想发一个 HTTP 请求,通常需要:
java
// 方式一:用 HttpURLConnection(难用)
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
// ... 一堆样板代码
// 方式二:用第三方库
HttpClient client = HttpClientBuilder.create().build(); // Apache HttpClient
// 依赖又多一个JDK 11 引入了标准 HTTP Client API,内置支持 HTTP/1.1 和 HTTP/2,同步和异步都能搞定。
快速上手
发送 GET 请求
java
import java.net.URI;
import java.net.http.*;
public class HttpClientDemo {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://jsonplaceholder.typicode.com/posts/1"))
.GET()
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.println("状态码: " + response.statusCode());
System.out.println("响应体: " + response.body());
}
}发送 POST 请求
java
HttpClient client = HttpClient.newHttpClient();
String requestBody = """
{
"title": "Hello",
"body": "World",
"userId": 1
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://jsonplaceholder.typicode.com/posts"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());核心组件
HttpClient
java
import java.net.http.*;
// 创建 HttpClient
HttpClient client = HttpClient.newHttpClient();
// 自定义配置
HttpClient client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2) // HTTP/2(默认)
// .version(HttpClient.Version.HTTP_1_1) // 强制 HTTP/1.1
.connectTimeout(Duration.ofSeconds(10))
.followRedirects(HttpClient.Redirect.NORMAL)
.build();HttpRequest
java
// GET 请求
HttpRequest getRequest = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/data"))
.GET()
.build();
// POST 请求
HttpRequest postRequest = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/submit"))
.header("Content-Type", "application/json")
.header("Authorization", "Bearer token123")
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
// PUT 请求
HttpRequest putRequest = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/resource/1"))
.header("Content-Type", "application/json")
.PUT(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
// DELETE 请求
HttpRequest deleteRequest = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/resource/1"))
.DELETE()
.build();异步请求
java
import java.net.http.*;
import java.util.concurrent.*;
public class AsyncDemo {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://jsonplaceholder.typicode.com/posts/1"))
.GET()
.build();
// 异步发送
CompletableFuture<HttpResponse<String>> future =
client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
// 注册回调
future.thenApply(HttpResponse::body)
.thenAccept(body -> System.out.println("响应: " + body))
.exceptionally(e -> {
System.err.println("请求失败: " + e.getMessage());
return null;
});
// 主线程继续做其他事
System.out.println("主线程继续执行...");
// 等待异步完成
Thread.sleep(2000);
}
}并发请求
java
import java.net.http.*;
import java.util.*;
public class ConcurrentDemo {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
List<String> urls = List.of(
"https://jsonplaceholder.typicode.com/posts/1",
"https://jsonplaceholder.typicode.com/posts/2",
"https://jsonplaceholder.typicode.com/posts/3"
);
List<HttpRequest> requests = urls.stream()
.map(url -> HttpRequest.newBuilder()
.uri(URI.create(url))
.GET()
.build())
.toList();
// 并发发送所有请求
List<CompletableFuture<HttpResponse<String>>> futures = requests.stream()
.map(req -> client.sendAsync(req, HttpResponse.BodyHandlers.ofString()))
.toList();
// 等待所有请求完成
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
// 收集结果
for (int i = 0; i < futures.size(); i++) {
HttpResponse<String> response = futures.get(i).get();
System.out.println("URL " + (i + 1) + ": " + response.statusCode());
}
}
}处理响应
响应体类型
java
// String
HttpResponse<String> stringResponse = client.send(request,
HttpResponse.BodyHandlers.ofString());
// ByteArray
HttpResponse<byte[]> bytesResponse = client.send(request,
HttpResponse.BodyHandlers.ofByteArray());
// File
HttpResponse<Void> fileResponse = client.send(request,
HttpResponse.BodyHandlers.ofFile(Path.of("response.json")));
// Discard(只关心状态码)
HttpResponse<Void> voidResponse = client.send(request,
HttpResponse.BodyHandlers.discarding());
// 自定义
HttpResponse<MyObject> customResponse = client.send(request,
HttpResponse.BodyHandlers.ofMapping(body -> parseJson(body)));响应头
java
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
// 获取单个头
String contentType = response.headers().firstValue("Content-Type").orElse("");
String date = response.headers().firstValue("Date").orElse("");
// 获取所有头
response.headers().map().forEach((name, values) -> {
System.out.println(name + ": " + values);
});处理表单数据
java
// application/x-www-form-urlencoded
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/login"))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(
"username=alice&password=secret"
))
.build();设置代理
java
HttpClient client = HttpClient.newBuilder()
.proxy(ProxySelector.of(new InetSocketAddress("proxy.example.com", 8080)))
.build();处理 Cookie
java
HttpClient client = HttpClient.newBuilder()
.cookieHandler(new CookieManager())
.build();
// 第一次请求(获取 Cookie)
HttpResponse<String> loginResponse = client.send(loginRequest,
HttpResponse.BodyHandlers.ofString());
// 后续请求(自动带上 Cookie)
HttpResponse<String> dataResponse = client.send(dataRequest,
HttpResponse.BodyHandlers.ofString());错误处理
java
try {
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
if (response.statusCode() >= 200 && response.statusCode() < 300) {
// 成功
System.out.println(response.body());
} else if (response.statusCode() == 404) {
// 资源不存在
System.out.println("Not Found");
} else {
// 其他错误
System.err.println("Error: " + response.statusCode());
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("请求被中断");
} catch (ExecutionException e) {
System.err.println("请求执行失败: " + e.getCause());
} catch (IOException e) {
System.err.println("网络错误: " + e.getMessage());
}小结
HTTP Client API 让 Java 原生 HTTP 请求变得简单:
| 特性 | 说明 |
|---|---|
| HTTP/1.1 + HTTP/2 | 默认 HTTP/2,自动协商 |
| 同步/异步 | send() 和 sendAsync() |
| 连接池 | 自动复用连接 |
| WebSocket | JDK 11+ 支持 |
| 内置 | 无需第三方依赖 |
java
// 最简用法
HttpResponse<String> response = HttpClient.newHttpClient()
.send(
HttpRequest.newBuilder().uri(URI.create(url)).GET().build(),
HttpResponse.BodyHandlers.ofString()
);从 JDK 11 开始,告别 HttpURLConnection 吧。
