杰瑞科技汇

Java HttpClient如何发送HTTP请求?

下面我将为你提供一个从入门到精通的完整指南,涵盖:

Java HttpClient如何发送HTTP请求?-图1
(图片来源网络,侵删)
  1. 基础入门:创建 HttpClient、发送 GET/POST 请求、处理响应。
  2. 进阶用法:设置请求头、处理请求体(JSON, Form)、添加超时、处理认证。
  3. 异步请求:如何非阻塞地发送请求。
  4. 与第三方库(如 Apache HttpClient)的对比

基础入门

1 创建 HttpClient

HttpClient 是一个可重用的对象,最佳实践是创建一个实例并在整个应用程序中共享它。

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
public class HttpClientBasicExample {
    public static void main(String[] args) throws Exception {
        // 1. 创建 HttpClient 实例
        // 可以配置连接超时、版本等
        HttpClient client = HttpClient.newBuilder()
                .version(HttpClient.Version.HTTP_2) // 使用 HTTP/2
                .connectTimeout(Duration.ofSeconds(10)) // 连接超时 10 秒
                .build();
        // 2. 创建 HttpRequest 请求对象
        // GET 请求示例:获取 JSONPlaceholder 的用户信息
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://jsonplaceholder.typicode.com/users/1"))
                .header("Accept", "application/json") // 设置 Accept 头
                .GET() // 显式指定 GET 方法
                .build();
        // 3. 发送请求并获取响应
        // 同步发送,会阻塞当前线程
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        // 4. 处理响应
        System.out.println("响应状态码: " + response.statusCode());
        System.out.println("响应头 Content-Type: " + response.headers().firstValue("Content-Type").orElse("N/A"));
        System.out.println("响应体:");
        System.out.println(response.body());
    }
}

运行结果:

响应状态码: 200
响应头 Content-Type: application/json; charset=utf-8
响应体:
{
  "id": 1,
  "name": "Leanne Graham",
  "username": "Bret",
  "email": "Sincere@april.biz",
  "address": {
    "street": "Kulas Light",
    "suite": "Apt. 556",
    "city": "Gwenborough",
    "zipcode": "92998-3874",
    "geo": {
      "lat": "-37.3159",
      "lng": "81.1496"
    }
  },
  "phone": "1-770-736-8031 x56442",
  "website": "hildegard.org",
  "company": {
    "name": "Romaguera-Crona",
    "catchPhrase": "Multi-layered client-server neural-net",
    "bs": "harness real-time e-markets"
  }
}

2 发送 POST 请求

发送 POST 请求通常需要包含请求体,下面是一个发送 JSON 数据的例子。

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Map;
public class HttpClientPostExample {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newBuilder().build();
        // 1. 准备要发送的 JSON 数据
        String jsonBody = "{\n" +
                "  \"title\": \"foo\",\n" +
                "  \"body\": \"bar\",\n" +
                "  \"userId\": 1\n" +
                "}";
        // 2. 创建 POST 请求
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://jsonplaceholder.typicode.com/posts"))
                .header("Content-Type", "application/json") // 设置 Content-Type 为 JSON
                .POST(HttpRequest.BodyPublishers.ofString(jsonBody)) // 设置请求体
                .build();
        // 3. 发送请求并获取响应
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        // 4. 处理响应
        System.out.println("响应状态码: " + response.statusCode());
        System.out.println("响应体:");
        System.out.println(response.body());
    }
}

进阶用法

1 设置请求头

可以在 HttpRequest.Builder 中使用 header(key, value) 方法链式调用添加多个请求头。

Java HttpClient如何发送HTTP请求?-图2
(图片来源网络,侵删)
HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://example.com/api"))
        .header("User-Agent", "My-Java-App/1.0")
        .header("Authorization", "Bearer your_token_here")
        .header("Accept-Language", "en-US,en;q=0.9")
        .GET()
        .build();

2 处理不同的请求体

除了 StringHttpClient 还支持多种请求体类型:

  • 字节数组: HttpRequest.BodyPublishers.ofByteArray(byte[] bytes)
  • 文件: HttpRequest.BodyPublishers.ofPath(Path path)
  • 输入流: HttpRequest.BodyPublishers.ofInputStream(Supplier<InputStream> inputStreamSupplier)

3 设置超时

有两种超时需要考虑:

  1. 连接超时:建立连接的超时时间,在创建 HttpClient 时设置。
  2. 请求超时:从发送请求到接收完整响应的超时时间,在发送请求时设置。
HttpClient client = HttpClient.newBuilder()
        .connectTimeout(Duration.ofSeconds(10))
        .build();
HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://example.com/slow-api"))
        .timeout(Duration.ofSeconds(30)) // 整个请求(包括读取响应体)超时 30 秒
        .GET()
        .build();

4 处理认证

HttpClient 内置了对基本认证和摘要认证的支持。

import java.net.Authenticator;
import java.net.PasswordAuthentication;
// 在发送请求前,设置全局的 Authenticator
Authenticator.setDefault(new Authenticator() {
    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
        // 如果请求的站点是需要认证的,这个方法会被调用
        if (getRequestingHost().equals("protected-site.com")) {
            return new PasswordAuthentication("username", "password".toCharArray());
        }
        return null;
    }
});
// 然后像平常一样发送请求
HttpClient client = HttpClient.newBuilder().build();
HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://protected-site.com/secure-data"))
        .GET()
        .build();

异步请求

异步请求不会阻塞调用线程,它依赖于 CompletableFuture 来处理结果。

Java HttpClient如何发送HTTP请求?-图3
(图片来源网络,侵删)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.concurrent.CompletableFuture;
public class HttpClientAsyncExample {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newBuilder().build();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://jsonplaceholder.typicode.com/users/1"))
                .build();
        // 发送异步请求,返回一个 CompletableFuture
        CompletableFuture<HttpResponse<String>> futureResponse = client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
        // 定义响应处理逻辑
        futureResponse.thenAccept(response -> {
            System.out.println("异步请求完成,状态码: " + response.statusCode());
            System.out.println("响应体: " + response.body());
        }).exceptionally(e -> {
            System.err.println("异步请求发生错误: " + e.getMessage());
            return null;
        });
        System.out.println("异步请求已发送,主线程继续执行其他任务...");
        // 为了让主线程等待异步任务完成(仅用于演示)
        // 在真实应用中,主线程不应该等待异步任务
        Thread.sleep(2000); 
    }
}

与 Apache HttpClient 的对比

虽然 Java 11+ 的 HttpClient 已经非常强大,但 Apache HttpClient 仍然在许多项目中广泛使用。

特性 Java 11+ HttpClient Apache HttpClient (4.x / 5.x)
依赖 JDK 标准库,无需额外依赖 需要添加 Maven/Gradle 依赖
API 风格 现代、函数式、Builder 模式 经典、面向对象
异步支持 基于 CompletableFuture,非常现代 基于 FutureAsyncCallback,成熟
HTTP/2 原生支持 需要额外配置或使用 5.x 版本
可配置性 良好,但相对简单 极高,连接池、路由、重试策略等配置非常灵活
社区与生态 由 Oracle 维护,是 Java 未来的方向 由 Apache 基金会维护,历史悠久,生态非常成熟
学习曲线 相对平缓 较陡峭,因为配置项非常多
  • 新项目或使用最新 JDK 的项目优先选择 Java 11+ HttpClient,它更轻量、更符合 Java 生态的未来趋势,API 设计也更优雅。
  • 遗留项目或需要复杂配置的项目:如果项目已经深度集成了 Apache HttpClient,或者需要其高度可配置的特性(如非常精细的连接池管理),继续使用 Apache HttpClient 是一个合理的选择。

Maven 依赖(如果需要使用 Apache HttpClient)

如果你因某些原因需要使用 Apache HttpClient,可以在 pom.xml 中添加以下依赖:

<!-- Apache HttpClient 5.x (推荐) -->
<dependency>
    <groupId>org.apache.httpcomponents.client5</groupId>
    <artifactId>httpclient5</artifactId>
    <version>5.3.1</version> <!-- 请使用最新版本 -->
</dependency>
<!-- 对应的 HTTP/5 支持 -->
<dependency>
    <groupId>org.apache.httpcomponents.core5</groupId>
    <artifactId>httpcore5</artifactId>
    <version>5.2</version> <!-- 请使用最新版本 -->
</dependency>

希望这份详细的指南能帮助你熟练掌握 Java 中的 HTTP 请求!

分享:
扫描分享到社交APP
上一篇
下一篇