ZetCode

Java HttpClient

最后修改日期:2025年4月17日

本 Java HttpClient 教程演示了如何在 Java 中使用 HttpClient 库来创建 HTTP 请求。它涵盖了构建简单的 GET 和 POST 请求,以及处理查询参数、异步请求、表单数据和超时等高级示例,为进行 HTTP 调用提供了全面的指南。

HTTP

超文本传输协议(HTTP是一种无状态的应用层协议,专为分布式、协作式、超媒体信息系统而设计。它支撑着万维网上的数据通信,使客户端(如 Web 浏览器或应用程序)能够从服务器请求资源并接收响应。HTTP 支持多种方法,如 GET、POST、PUT 和 DELETE,从而促进了各种操作,例如检索网页、提交表单或更新服务器数据。

在本教程中,我们使用 httpbin.org,这是一个免费的开源 HTTP 请求和响应服务,提供了用于测试各种 HTTP 操作(包括重定向、身份验证和数据操作)的端点。此外,我们还利用 webcode.me,这是一个专为测试 HTTP 请求而设计的轻量级 HTML 页面,为我们的示例提供了一个简单可靠的目标。

方法 描述 常见用例 幂等
GET 请求指定资源的表示形式,而不修改它。 检索网页、获取 API 数据、访问图像或文件。
POST 向服务器提交数据以创建或更新资源。 提交表单、上传文件、创建新的数据库记录。
PUT 用提供的数据替换或更新资源。 更新用户个人资料、替换文件、修改 API 资源。
DELETE 从服务器中删除指定的资源。 删除用户帐户、移除数据库条目、擦除文件。
HEAD 请求资源的头部信息,而不检索其主体。 检查资源元数据、验证链接有效性、测试服务器响应。

HTTP 中的幂等性指的是某些方法的属性,即多次重复相同的请求会产生相同的结果,而不会在服务器上产生额外的副作用。幂等方法(如 GET、PUT、DELETE 和 HEAD)确保后续相同的请求不会在初始请求之外改变服务器的状态,这使得它们在出现网络问题时可以安全重试。相比之下,像 POST 这样的非幂等方法每次都可能创建新资源,每次请求都会影响服务器的状态。

HttpClient

在 Java 11 中引入的 HttpClient 库提供了一个现代、灵活且功能强大的 API,用于在 Java 中发出 HTTP 请求。在 Java 11 之前,开发人员通常使用功能简陋的 URLConnection 类(它缺乏高级功能),或者依赖于像 Apache HttpClient 或 OkHttp 这样的第三方库来实现健壮的 HTTP 通信。内置的 HttpClient 通过流线型的链式 API 和对同步及异步请求的原生支持,简化了 HTTP 操作。

Java HttpClient 支持 HTTP/1.1 和 HTTP/2 协议,默认使用 HTTP/2 以通过多路复用和头部压缩等特性获得更好的性能。如果服务器不支持 HTTP/2,客户端会自动降级到 HTTP/1.1,以确保兼容性。此外,HttpClient 提供了重定向处理、身份验证和超时等高级功能,使其成为现代 Web 交互的多功能工具。

client = HttpClient.newHttpClient();
client = HttpClient.newBuilder().build();

您可以通过两种方式创建 HttpClient 实例:使用 newHttpClient 创建具有默认设置的客户端,或使用 newBuilder 创建可自定义的客户端,您可以在其中配置超时、重定向策略或代理设置等选项。这些方法为构建满足您应用程序需求的 HTTP 请求提供了基础。

HttpClient 状态

在第一个示例中,我们检查一个网页的状态。

Main.java
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

void main() throws IOException, InterruptedException {

    try (HttpClient client = HttpClient.newHttpClient()) {

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://webcode.me"))
                .GET() // GET is default
                .build();

        HttpResponse<Void> response = client.send(request,
                HttpResponse.BodyHandlers.discarding());

        System.out.println(response.statusCode());
    }
}

此示例创建一个到 webcode.me 网站的 GET 请求并检索 HTTP 响应。我们从响应中提取状态码。

HttpClient client = HttpClient.newHttpClient();

创建了一个新的 HttpClient 实例。

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("http://webcode.me"))
    .GET() // GET is default
    .build();

构造了一个新的 HttpRequest。我们指定了 URI 和请求方法。(如果未指定方法,则默认使用 GET。)

HttpResponse response = client.send(request,
    HttpResponse.BodyHandlers.discarding());

我们发送请求。由于我们对响应主体不感兴趣,我们使用 HttpResponse.BodyHandlers.discarding 将其丢弃。

System.out.println(response.statusCode());

我们使用 statusCode 方法检索状态码。

HEAD 请求

HEAD 请求是一种没有消息主体的 GET 请求。

Main.java
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpHeaders;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

void main() throws IOException, InterruptedException {

    try (HttpClient client = HttpClient.newHttpClient()) {

        var request = HttpRequest.newBuilder(URI.create("https://webcode.me"))
                .method("HEAD", HttpRequest.BodyPublishers.noBody())
                .build();

        HttpResponse<Void> response = client.send(request,
                HttpResponse.BodyHandlers.discarding());

        HttpHeaders headers = response.headers();

        headers.map().forEach((key, values) -> {
            System.out.printf("%s: %s%n", key, values);
        });
    }
}

此示例构造一个 HEAD 请求。

var request = HttpRequest.newBuilder(URI.create("https://webcode.me"))
    .method("HEAD", HttpRequest.BodyPublishers.noBody())
    .build();

我们创建一个 HEAD 请求。由于请求不包含主体,我们使用 HttpRequest.BodyPublishers.noBody

HttpResponse response = client.send(request,
    HttpResponse.BodyHandlers.discarding());

我们发送请求并接收响应。

HttpHeaders headers = response.headers();

headers.map().forEach((key, values) -> {
    System.out.printf("%s: %s%n", key, values);
});

我们从响应中获取头部信息并在控制台上显示它们。

$ java Main.java
accept-ranges: [bytes]
connection: [keep-alive]
content-length: [395]
content-type: [text/html]
date: [Wed, 09 Oct 2024 13:22:09 GMT]
etag: ["64f33c9f-18b"]
last-modified: [Sat, 02 Sep 2023 13:46:07 GMT]
server: [nginx/1.18.0 (Ubuntu)]

GET 请求

HTTP GET 方法请求指定资源的表示形式。使用 GET 的请求应该只用于检索数据。

Main.java
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

void main() throws IOException, InterruptedException {

    try (HttpClient client = HttpClient.newHttpClient()) {

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://webcode.me"))
                .build();

        HttpResponse<String> response = client.send(request,
                HttpResponse.BodyHandlers.ofString());

        System.out.println(response.body());
    }
}

我们生成一个到 webcode.me 网页的 GET 请求。

try (HttpClient client = HttpClient.newHttpClient()) {

使用 newHttpClient 工厂方法实例化一个新的 HttpClient

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://webcode.me"))
    .build();

我们构造一个到该网页的同步请求。默认方法是 GET。

HttpResponse response = client.send(request,
    HttpResponse.BodyHandlers.ofString());

System.out.println(response.body());

我们发送请求,检索响应内容,并将其打印到控制台。我们使用 HttpResponse.BodyHandlers.ofString,因为我们期望得到一个 HTML 字符串响应。

文件 BodyHandler

通过文件 body handler,我们可以方便地将响应文本保存到文件中。

Main.java
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Path;
import java.nio.file.Paths;

void main() throws IOException, InterruptedException {

    try (HttpClient client = HttpClient.newHttpClient()) {

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://webcode.me"))
                .GET() // GET is default
                .build();

        String fileName = "src/main/resources/index.html";

        HttpResponse<Path> response = client.send(request,
                HttpResponse.BodyHandlers.ofFile(Paths.get(fileName)));

        System.out.println(response.statusCode());
    }
}

此示例将 HTML 页面保存到 src/main/resources/index.html

String fileName = "src/main/resources/index.html";

HttpResponse<Path> response = client.send(request,
        HttpResponse.BodyHandlers.ofFile(Paths.get(fileName)));

文件 body handler 是使用 HttpResponse.BodyHandlers.ofFile 创建的。

POST 请求

HTTP POST 方法将数据传输到服务器。它通常用于上传文件或提交已完成的 Web 表单。

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.11.0</version>
</dependency>

我们需要 gson 依赖项。

Main.java
import com.google.gson.Gson;

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.HashMap;

void main() throws IOException, InterruptedException {

    var values = new HashMap<String, String>() {{
        put("name", "John Doe");
        put("occupation", "gardener");
    }};

    Gson gson = new Gson();
    String requestBody = gson.toJson(values);

    try (HttpClient client = HttpClient.newHttpClient()) {

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://httpbin.org/post"))
                .POST(HttpRequest.BodyPublishers.ofString(requestBody))
                .build();

        HttpResponse<String> response = client.send(request,
                HttpResponse.BodyHandlers.ofString());

        System.out.println(response.body());
    }
}

我们向 https://httpbin.org/post 页面发送一个 POST 请求。

var values = new HashMap<String, String>() {{
    put("name", "John Doe");
    put("occupation", "gardener");
}};

Gson gson = new Gson();
String requestBody = gson.toJson(values);

首先,我们使用 Gson 构造请求主体。

try (HttpClient client = HttpClient.newHttpClient()) {
    
    HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://httpbin.org/post"))
            .POST(HttpRequest.BodyPublishers.ofString(requestBody))
            .build();
    ...
}

我们创建 POST 请求。通过 BodyPublishers.ofString,我们生成一个新的 BodyPublisher。它将高级 Java 对象转换为适合作为请求主体发送的字节缓冲区流。

HttpResponse<String> response = client.send(request,
        HttpResponse.BodyHandlers.ofString());

System.out.println(response.body());

我们发送请求并检索响应。

HttpClient 重定向

重定向涉及将一个 URL 转发到另一个 URL。HTTP 响应状态码 301 Moved Permanently 表示永久 URL 重定向,而 302 Found 表示临时重定向。

Main.java
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

// toggle HttpClient.Redirect.ALWAYS / HttpClient.Redirect.NEVER

void main() throws IOException, InterruptedException {

    try (HttpClient client = HttpClient.newBuilder()
            .followRedirects(HttpClient.Redirect.ALWAYS).build()) {

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://httpbin.org/redirect/3"))
                .GET()
                .build();

        HttpResponse<Void> response = client.send(request,
                HttpResponse.BodyHandlers.discarding());

        System.out.println(response.statusCode());
    }
}

在此示例中,我们发送一个被重定向的请求。

try (HttpClient client = HttpClient.newBuilder()
        .followRedirects(HttpClient.Redirect.ALWAYS).build()) {
    ...
}

要配置重定向,我们使用 followRedirects 方法。

HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://httpbin.org/redirect/3"))
        .GET()
        .build();

URL https://httpbin.org/redirect/3 是一个测试端点,它会将请求重定向三次。

HttpResponse response = client.send(request,
        HttpResponse.BodyHandlers.discarding());

System.out.println(response.statusCode());

请求被发送,并显示响应状态。

HttpClient 读取 Favicon

以下示例从网站检索一个小图像。

Main.java
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

void main() throws IOException, InterruptedException {

    try (HttpClient client = HttpClient.newHttpClient()) {

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://webcode.me/favicon.ico"))
                .build();

        HttpResponse<byte[]> response = client.send(request,
                HttpResponse.BodyHandlers.ofByteArray());

        byte[] data = response.body();

        int i = 0;
        for (byte c : data) {

            System.out.printf("%02x ", c);

            i++;

            if (i % 10 == 0) {

                System.out.println();
            }
        }
    }
}

此示例从一个网站获取一个 favicon,并以十六进制格式打印其内容。

HttpResponse<byte[]> response = client.send(request,
    HttpResponse.BodyHandlers.ofByteArray());

使用 HttpResponse.BodyHandlers.ofByteArray,我们读取二进制数据。

byte[] data = response.body();

我们从响应主体中提取字节数组。

int i = 0;
for (byte c : data) {

    System.out.printf("%02x ", c);

    i++;

    if (i % 10 == 0) {

        System.out.println();
    }
}

在一个 for 循环中,我们以十六进制格式打印这些字节。

带查询参数的 GET 请求

此示例演示如何在 GET 请求中包含查询参数。

Main.java
import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;

void main() throws IOException, InterruptedException {

    String query = "name=" + URLEncoder.encode("John Doe", StandardCharsets.UTF_8) +
                   "&occupation=" + URLEncoder.encode("gardener", StandardCharsets.UTF_8);

    try (HttpClient client = HttpClient.newHttpClient()) {

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://httpbin.org/get?" + query))
                .GET()
                .build();

        HttpResponse<String> response = client.send(request,
                HttpResponse.BodyHandlers.ofString());

        System.out.println(response.body());
    }
}

此示例向 https://httpbin.org/get 发送一个带查询参数的 GET 请求。

String query = "name=" + URLEncoder.encode("John Doe", StandardCharsets.UTF_8) +
               "&occupation=" + URLEncoder.encode("gardener", StandardCharsets.UTF_8);

我们构造查询字符串,对参数进行编码以处理特殊字符。

HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://httpbin.org/get?" + query))
        .GET()
        .build();

查询字符串被附加到 GET 请求的 URL 中。

异步 GET 请求

此示例展示了如何使用 HttpClient 执行异步 GET 请求。

Main.java
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

void main() {

    try (HttpClient client = HttpClient.newHttpClient()) {

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://webcode.me"))
                .GET()
                .build();

        CompletableFuture<HttpResponse<String>> responseFuture = client.sendAsync(request,
                HttpResponse.BodyHandlers.ofString());

        responseFuture.thenAccept(response -> {
            System.out.println("Status Code: " + response.statusCode());
            System.out.println("Body: " + response.body());
        }).join();
    }
}

此示例发送一个异步 GET 请求,并在响应到达时处理它。

CompletableFuture<HttpResponse<String>> responseFuture = client.sendAsync(request,
        HttpResponse.BodyHandlers.ofString());

sendAsync 方法返回一个用于异步处理的 CompletableFuture

responseFuture.thenAccept(response -> {
    System.out.println("Status Code: " + response.statusCode());
    System.out.println("Body: " + response.body());
}).join();

我们使用 thenAccept 处理响应,并用 join 等待完成。

带表单数据的 POST 请求

此示例演示如何发送带有表单数据的 POST 请求。

Main.java
import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

void main() throws IOException, InterruptedException {

    Map<String, String> formData = new HashMap<>();
    formData.put("username", "john_doe");
    formData.put("email", "john@example.com");

    String requestBody = formData.entrySet().stream()
            .map(entry -> URLEncoder.encode(entry.getKey(), 
                StandardCharsets.UTF_8) + "=" + URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8))
            .collect(Collectors.joining("&"));

    try (HttpClient client = HttpClient.newHttpClient()) {

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://httpbin.org/post"))
                .header("Content-Type", "application/x-www-form-urlencoded")
                .POST(HttpRequest.BodyPublishers.ofString(requestBody))
                .build();

        HttpResponse<String> response = client.send(request,
                HttpResponse.BodyHandlers.ofString());

        System.out.println(response.body());
    }
}

此示例向 https://httpbin.org/post 发送一个带有表单数据的 POST 请求。

String requestBody = formData.entrySet().stream()
        .map(entry -> URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8) + "=" +
                      URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8))
        .collect(Collectors.joining("&"));

我们将表单数据编码为 URL 编码的字符串。

.header("Content-Type", "application/x-www-form-urlencoded")

我们设置 Content-Type 头部以指示表单数据。

带超时的 HttpClient

此示例展示了如何为 HTTP 请求配置超时。

Main.java
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

void main() throws InterruptedException {

    try (HttpClient client = HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(5))
            .build()) {

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://httpbin.org/delay/10"))
                .timeout(Duration.ofSeconds(3))
                .GET()
                .build();

        try {
            HttpResponse<String> response = client.send(request,
                    HttpResponse.BodyHandlers.ofString());
            System.out.println(response.body());
        } catch (IOException e) {
            System.err.println("Request timed out: " + e.getMessage());
        }
    }
}

此示例设置了连接超时和请求超时,并处理超时异常。

try (HttpClient client = HttpClient.newBuilder()
        .connectTimeout(Duration.ofSeconds(5))
        .build()) {

我们为客户端设置了 5 秒的连接超时。

.timeout(Duration.ofSeconds(3))

我们为请求设置了 3 秒的超时。

try {
    HttpResponse<String> response = client.send(request,
            HttpResponse.BodyHandlers.ofString());
    System.out.println(response.body());
} catch (IOException e) {
    System.err.println("Request timed out: " + e.getMessage());
}

我们捕获并处理超时异常。

PUT 请求

此示例演示如何发送 PUT 请求以更新服务器上的数据。

Main.java
import com.google.gson.Gson;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.HashMap;

void main() throws IOException, InterruptedException {

    var values = new HashMap<String, String>() {{
        put("name", "Jane Doe");
        put("occupation", "developer");
    }};

    Gson gson = new Gson();
    String requestBody = gson.toJson(values);

    try (HttpClient client = HttpClient.newHttpClient()) {

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://httpbin.org/put"))
                .header("Content-Type", "application/json")
                .method("PUT", HttpRequest.BodyPublishers.ofString(requestBody))
                .build();

        HttpResponse<String> response = client.send(request,
                HttpResponse.BodyHandlers.ofString());

        System.out.println(response.body());
    }
}

此示例向 https://httpbin.org/put 发送一个带有 JSON 数据的 PUT 请求。

var values = new HashMap<String, String>() {{
    put("name", "Jane Doe");
    put("occupation", "developer");
}};

Gson gson = new Gson();
String requestBody = gson.toJson(values);

我们使用 Gson 为 PUT 请求创建一个 JSON 负载。

.header("Content-Type", "application/json")

我们设置 Content-Type 头部以指示 JSON 数据。

.method("PUT", HttpRequest.BodyPublishers.ofString(requestBody))

我们指定 PUT 方法,并在请求主体中包含 JSON 负载。

处理 JSON 响应

此示例展示了如何解析来自 GET 请求的 JSON 响应。

Main.java
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

void main() throws IOException, InterruptedException {

    try (HttpClient client = HttpClient.newHttpClient()) {

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://httpbin.org/get"))
                .GET()
                .build();

        HttpResponse<String> response = client.send(request,
                HttpResponse.BodyHandlers.ofString());

        Gson gson = new Gson();
        JsonObject jsonResponse = gson.fromJson(response.body(), JsonObject.class);

        String url = jsonResponse.get("url").getAsString();
        System.out.println("Requested URL: " + url);
    }
}

此示例发送一个 GET 请求并解析 JSON 响应以提取特定数据。

HttpResponse<String> response = client.send(request,
        HttpResponse.BodyHandlers.ofString());

我们将响应主体检索为字符串。

Gson gson = new Gson();
JsonObject jsonResponse = gson.fromJson(response.body(), JsonObject.class);

我们使用 Gson 将响应主体解析为 JSON 对象。

String url = jsonResponse.get("url").getAsString();
System.out.println("Requested URL: " + url);

我们从 JSON 响应中提取并打印 "url" 字段。

自定义头部

此示例演示如何向 HTTP 请求添加自定义头部。

Main.java
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

void main() throws IOException, InterruptedException {

    try (HttpClient client = HttpClient.newHttpClient()) {

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://httpbin.org/headers"))
                .header("X-Custom-Header", "MyCustomValue")
                .header("User-Agent", "Java HttpClient client")
                .GET()
                .build();

        HttpResponse<String> response = client.send(request,
                HttpResponse.BodyHandlers.ofString());

        System.out.println(response.body());
    }
}

此示例向 https://httpbin.org/headers 发送一个带有自定义头部的 GET 请求。

.header("X-Custom-Header", "MyCustomValue")

我们添加一个名为 X-Custom-Header 并带有特定值的自定义头部。

.header("User-Agent", "Java HttpClient client")

我们用一个自定义值覆盖默认的 User-Agent 头部。

HttpResponse<String> response = client.send(request,
        HttpResponse.BodyHandlers.ofString());

System.out.println(response.body());

我们发送请求并打印响应,其中包含已发送的头部。

流式响应数据

此示例展示了如何将响应作为行流来处理。

Main.java
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.stream.Stream;

void main() throws IOException, InterruptedException {

    try (HttpClient client = HttpClient.newHttpClient()) {

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://httpbin.org/stream/5"))
                .GET()
                .build();

        HttpResponse<Stream<String>> response = client.send(request,
                HttpResponse.BodyHandlers.ofLines());

        response.body().forEach(line -> System.out.println("Line: " + line));
    }
}

此示例发送一个 GET 请求,并将响应作为行流进行处理。

HttpResponse<Stream<String>> response = client.send(request,
        HttpResponse.BodyHandlers.ofLines());

我们使用 BodyHandlers.ofLines 将响应作为字符串流来处理。

response.body().forEach(line -> System.out.println("Line: " + line));

我们遍历行流并打印每一行。

DELETE 请求

此示例演示如何发送 DELETE 请求以从服务器删除资源。

Main.java
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

void main() throws IOException, InterruptedException {

    try (HttpClient client = HttpClient.newHttpClient()) {

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://httpbin.org/delete"))
                .method("DELETE", HttpRequest.BodyPublishers.noBody())
                .build();

        HttpResponse<String> response = client.send(request,
                HttpResponse.BodyHandlers.ofString());

        System.out.println("Status Code: " + response.statusCode());
        System.out.println("Response: " + response.body());
    }
}

此示例向 https://httpbin.org/delete 发送一个 DELETE 请求并打印响应。

HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://httpbin.org/delete"))
        .method("DELETE", HttpRequest.BodyPublishers.noBody())
        .build();

我们使用 BodyPublishers.noBody 创建一个没有主体的 DELETE 请求。

HttpResponse<String> response = client.send(request,
        HttpResponse.BodyHandlers.ofString());

我们发送请求并以字符串形式检索响应。

System.out.println("Status Code: " + response.statusCode());
System.out.println("Response: " + response.body());

我们打印状态码和响应主体以验证请求的结果。

HTTP 基本身份验证

此示例展示了如何在请求中包含 HTTP 基本身份验证。

Main.java
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.Base64;

void main() throws IOException, InterruptedException {

    String credentials = Base64.getEncoder().encodeToString("user:passwd".getBytes());

    try (HttpClient client = HttpClient.newHttpClient()) {

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://httpbin.org/basic-auth/user/passwd"))
                .header("Authorization", "Basic " + credentials)
                .GET()
                .build();

        HttpResponse<String> response = client.send(request,
                HttpResponse.BodyHandlers.ofString());

        System.out.println("Status Code: " + response.statusCode());
        System.out.println("Response: " + response.body());
    }
}

此示例向 https://httpbin.org/basic-auth/user/passwd 发送一个带有基本身份验证的 GET 请求。

String credentials = Base64.getEncoder().encodeToString("user:passwd".getBytes());

我们将用户名和密码编码为 Base64 格式以用于基本身份验证。

.header("Authorization", "Basic " + credentials)

我们添加带有编码凭据的 Authorization 头部。

HttpResponse<String> response = client.send(request,
        HttpResponse.BodyHandlers.ofString());

System.out.println("Status Code: " + response.statusCode());
System.out.println("Response: " + response.body());

我们发送请求并打印状态码和响应主体。

并发请求

此示例演示如何使用 HttpClient 并发发送多个 HTTP 请求。

Main.java
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

void main() {

    try (HttpClient client = HttpClient.newHttpClient()) {

        List<HttpRequest> requests = List.of(
                HttpRequest.newBuilder().uri(URI.create("https://httpbin.org/get")).GET().build(),
                HttpRequest.newBuilder().uri(URI.create("https://webcode.me")).GET().build()
        );

        List<CompletableFuture<HttpResponse<String>>> futures = requests.stream()
                .map(request -> client.sendAsync(request, HttpResponse.BodyHandlers.ofString()))
                .toList();

        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

        for (CompletableFuture<HttpResponse<String>> future : futures) {
            HttpResponse<String> response = future.join();
            System.out.println("Status: " + response.statusCode() + ", URI: " + response.uri());
        }
    }
}

此示例并发发送多个 GET 请求并处理它们的响应。

List<HttpRequest> requests = List.of(
    HttpRequest.newBuilder().uri(URI.create("https://httpbin.org/get")).GET().build(),
    HttpRequest.newBuilder().uri(URI.create("https://webcode.me")).GET().build()
);

我们创建一个要并发发送的 HTTP 请求列表。

List<CompletableFuture<HttpResponse<String>>> futures = requests.stream()
        .map(request -> client.sendAsync(request, HttpResponse.BodyHandlers.ofString()))
        .toList();

我们使用 sendAsync 将每个请求映射到一个异步的 CompletableFuture

CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

for (CompletableFuture<HttpResponse<String>> future : futures) {
    HttpResponse<String> response = future.join();
    System.out.println("Status: " + response.statusCode() + ", URI: " + response.uri());
}

我们等待所有请求完成,并打印它们的状态码和 URI。

来源

Java HttpClient - 语言参考

在本文中,我们利用 Java HttpClient 创建了 HTTP 请求。

作者

我叫 Jan Bodnar,我是一名充满热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。至今,我已经创作了超过 1400 篇文章和 8 本电子书。我拥有超过八年的编程教学经验。

查看所有 Java 教程