Http‘CLient



package chapter15;
 
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
 
public class HttpClientDemo {
    public static void main(String[] args) throws Exception {
 
        HttpClient httpClient = HttpClient.newHttpClient();
 
        URI uri = URI.create("https://www.xdclass.net/");
 
        HttpRequest.Builder builder = HttpRequest.newBuilder();
 
        HttpRequest httpRequest = builder.uri(uri).build();
 
        HttpResponse<String> httpResponse = httpClient.send(httpRequest,HttpResponse.BodyHandlers.ofString());
 
        System.out.println("响应状态码:" + httpResponse.statusCode());
 
        System.out.println("响应体:" + httpResponse.body());
 
    }
}

HttpClient httpClient = HttpClient.newHttpClient();

作用: 创建一个 HttpClient 的实例。

目的: 这是我们发起所有网络请求的“发起者”。

详解:

HttpClient.newHttpClient() 是一个静态工厂方法,它会创建一个具有默认配置的 HttpClient。

这个 httpClient 对象是高度可复用的。在实际应用中,你应该只创建一个 HttpClient 实例,然后在整个应用程序中共享它来发送多个请求。它内部管理着连接池和线程等资源,复用可以大大提高性能。


URI uri = URI.create("https://www.xdclass.net/");

作用: 根据一个字符串创建一个 URI 对象。

目的: 为即将构建的 HTTP 请求提供一个格式正确、经过验证的目标地址。使用 URI 类型比直接使用 String 更健壮,因为 URI.create() 会检查语法的正确性。


HttpRequest.Builder builder = HttpRequest.newBuilder();

作用: 创建一个 HttpRequest 的构造器(Builder)。

目的: 这是建造者模式(Builder Pattern)的运用。HttpRequest 对象被设计成不可变的(Immutable),意味着一旦创建就不能修改。建造者模式提供了一种流畅、可读性强的方式来分步构建这个复杂的不可变对象。你先创建一个“蓝图”(Builder),在上面设置各种属性,最后再一次性“建造”出最终的对象。


HttpRequest httpRequest = builder.uri(uri).build();

作用: 使用 builder 来配置并最终构建出 HttpRequest 对象。

目的: 生成一个代表我们意图的、完整的请求对象。

详解:

builder.uri(uri): 在 builder 上设置请求的目标 URI。这个方法会返回 builder 本身,这使得方法链式调用成为可能(例如 builder.uri(uri).header(…).GET())。

.build(): 这是建造过程的最后一步。它会收集所有在 builder 上设置的信息,并创建一个最终的、不可变的 HttpRequest 实例。

注意: 我们没有明确指定请求方法(如 .GET() 或 .POST(…))。在这种情况下,API 默认使用 GET 方法,这对于访问网页来说是最常见的操作。


HttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());

作用: 发送 HTTP 请求并获取响应。这是整个程序中最核心的一步。

目的: 执行实际的网络通信。

详解:

httpClient.send(…): 这是一个同步方法,意味着代码会在这里阻塞(等待),直到服务器的完整响应被接收回来。

httpRequest: 第一个参数,是我们刚刚构建的请求对象。

HttpResponse.BodyHandlers.ofString(): 第二个参数,这是一个响应体处理器 (Body Handler)。它告诉 HttpClient 应该如何处理接收到的响应体数据

ofString() 这个处理器表示:“请将服务器返回的原始字节流,根据响应头中 Content-Type 指定的字符集(如果未指定,则默认为 UTF-8)解码成一个 Java String。”

这个 API 非常灵活,还提供了其他处理器,如 ofByteArray() (处理成字节数组)、ofFile(path) (直接存为文件)、discarding() (忽略响应体)等。

HttpResponse<String>: send 方法的返回类型。泛型 <String> 与我们提供的 BodyHandlers.ofString() 相匹配,这是一种类型安全的设计。如果我们用了 ofByteArray(),这里的类型就会是 HttpResponse<byte[]>。


System.out.println("响应状态码:" + httpResponse.statusCode());

作用: 从响应对象中获取状态码并打印到控制台。

目的: 检查请求是否成功。

详解:

httpResponse.statusCode(): 返回一个 int 类型的值,代表 HTTP 状态码。常见的值有:

200: OK (成功)

404: Not Found (未找到)

500: Internal Server Error (服务器内部错误)


System.out.println("响应体:" + httpResponse.body());

作用: 从响应对象中获取响应体并打印到控制台。

目的: 查看从服务器获取到的实际内容。

详解:

httpResponse.body(): 返回响应体。因为我们在 send 方法中指定了 BodyHandlers.ofString(),所以这个方法的返回值类型就是 String。对于一个网页请求,这里打印出的将会是该网页的 HTML 源代码。



}
}

main 方法和 HttpClientDemo 类的结束括号。


3. 代码核心思想与要点

现代化与流畅性: 整个 API 设计采用了现代 Java 的风格,如工厂方法 (newHttpClient)、建造者模式和方法链式调用,使得代码非常清晰易读。

不可变性: HttpRequest 和 HttpResponse 都是不可变对象,这使得它们在多线程环境中是线程安全的,可以安全地共享。

灵活性: 通过不同的 BodyHandler,可以非常灵活地决定如何处理响应数据,无论是转为字符串、存为文件还是直接丢弃,都非常方便。

同步与异步: 代码中展示的是 send() 同步方法,API 还提供了一个 sendAsync() 方法,它会返回一个 CompletableFuture,用于进行非阻塞的异步编程,这在构建高性能网络应用时非常有用。

案例比喻

一、把互联网想象成一个巨大的邮政系统

你的电脑: 就是你自己,寄信人

服务器 (Server): 就是收信人,比如 “小顶课堂”(xdclass.net)的总部。服务器本质上也是一台电脑,但它24小时开机,专门用来存放网站内容并等待别人来索取。

互联网: 就是连接你和总部的邮政网络(包括邮筒、邮局、卡车、飞机等)。

二-A、代码在做什么:寄信请求的过程

现在,我们把你的Java代码和寄信的步骤一一对应起来。



// 准备工作1: 找一个可靠的快递公司
HttpClient httpClient = HttpClient.newHttpClient();

HTTP Client (客户端): 把它想象成一个快递公司,比如顺丰或邮政。它是一个专业的机构,知道所有寄信的规则、路线和如何处理各种问题。你不需要自己跑去送信,你只需要把信交给它就行。

代码含义: “嘿,Java,给我找一家默认的、可靠的‘HTTP快递公司’,我接下来要用它寄信。”



// 准备工作2: 写下收信人的地址
URI uri = URI.create("https://www.xdclass.net/");

URI (统一资源标识符): 这就是收信人的地址,写得非常标准,邮递员一看就懂。

https://: 表示这封信需要加密传输(像是一个加密的保险箱),保证内容不被偷看。

www.xdclass.net: 就是收信人的具体门牌号,“小顶课堂网站总部”。

代码含义: “我要把信寄到这个地址去。”



// 准备工作3: 准备信封和信纸
HttpRequest.Builder builder = HttpRequest.newBuilder();
HttpRequest httpRequest = builder.uri(uri).build();

HTTP Request (请求): 这就是你准备的一封完整的信。一封信包括:

信封: 上面写着收信人地址(uri)。

信的内容: 对于这次请求,信的内容是空的,因为我们只是去“要东西”,而不是“送东西”。

寄信方式 (Method): 你是怎么寄的?是要求对方给你回信(GET),还是你要寄东西给对方(POST)?

GET (获取): 就像你寄一张明信片,上面写着:“你好,请把你们最新的宣传手册寄给我一份。” 你的代码默认就是用的GET方式。

POST (提交): 就像你寄一个包裹,里面装着你填好的报名表。

代码含义: “请准备一封信(HttpRequest),信封上写好刚才那个地址。信的内容是空的,因为我只是想从他们那里**获取(GET)**一些信息。”



// 行动: 把信交给快递公司,并告诉他们回信怎么处理
HttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());

httpClient.send(…): 这是**“寄出”**这个动作。你把准备好的信交给了快递公司。

代码会在这里停下等待: 快递员需要时间去送信,对方也需要时间准备回信,然后快递员再把回信送回来。所以你的程序会在这里“暂停”,直到收到回信为止。

HttpResponse.BodyHandlers.ofString(): 这是你给快递员的一个特别指示:“对方的回信(HttpResponse)可能是用密码(字节流)写的,你收到后,请帮我翻译成我能看懂的文字(String)。”

HttpResponse<String> httpResponse: httpResponse 就是快递员最终送回给你的回信。<String> 表示这封信的内容已经被翻译成了文字。

二-B、代码在做什么:查看回信的过程



// 查看回信1: 看信封上的邮戳和状态
System.out.println("响应状态码:" + httpResponse.statusCode());

HTTP Response (响应): 这就是服务器(小顶课堂总部)给你的回信。

Status Code (状态码): 这就像回信信封上的一个盖章或标签,告诉你对方处理你的请求的结果。

200: “请求收到,你要的东西就在信里,一切顺利!” (OK)

404: “你请求的那个部门或资料我们这里没有,地址是不是写错了?” (Not Found)

代码含义: “看看回信上的状态章,确认一下对方是不是成功处理了我的请求。”



// 查看回信2: 读信里的具体内容
System.out.println("响应体:" + httpResponse.body());

Body (响应体): 这就是回信的正文内容。因为你之前请求的是网页,所以这个正文就是那个网站的全部HTML代码(可以理解为网页的“骨架”描述语言)。

代码含义: “好了,现在打开信封,大声把信里的内容读出来。” 你会在屏幕上看到一大堆 <html>…</html> 这样的代码。


总结

所以,你的Java代码完整地模拟了这个过程:

找了家快递公司 (HttpClient)。

写好了收信地址 (URI)。

准备了一封“索要资料”的信 (HttpRequest)。

把信寄出去,并耐心等待回信 (send)。

收到回信后,先看处理结果盖章 (statusCode)。

再读回信的正文内容 (body)。

© 版权声明

相关文章

暂无评论

none
暂无评论...