HttpClient 详解
Feat HttpClient 是一个功能强大、灵活且高效的 HTTP 客户端库,旨在帮助开发者轻松发送 HTTP 请求、处理响应。无论你是要调用第三方 API,还是构建微服务间的通信,HttpClient 都能胜任。
在开始使用 Feat HttpClient 之前,我们需要先引入相关依赖。
在 Maven 项目中,添加以下依赖到 pom.xml:
<dependency> <groupId>tech.smartboot.feat</groupId> <artifactId>feat-core</artifactId> <version>${feat.version}</version></dependency>发送第一个 GET 请求
Section titled “发送第一个 GET 请求”万事开头难,让我们从一个简单的例子开始。下面的示例展示了如何使用 Feat HttpClient 发送 GET 请求并处理响应:
import tech.smartboot.feat.core.client.HttpClient;import java.io.IOException;
public class HttpClientDemo { public static void main(String[] args) throws IOException { // 创建 HttpClient 实例 HttpClient client = new HttpClient("https://www.baidu.com");
// 发送 GET 请求 client.get().onSuccess(response -> { // 处理响应 System.out.println("Status Code: " + response.statusCode()); System.out.println("Body: " + response.body()); }).submit(); }}是不是很简单?接下来我们会深入了解 HttpClient 的各种功能。
API 接口说明
Section titled “API 接口说明”| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
HttpClient(String url) | url: 完整的请求 URL | HttpClient | 创建 HttpClient 实例 |
HttpClient(String host, int port) | host: 主机地址 port: 端口号 | HttpClient | 创建 HttpClient 实例 |
options() | - | HttpClientOptions | 获取配置选项 |
get(String path) | path: 请求路径 | HttpRequest | 创建 GET 请求 |
post(String path) | path: 请求路径 | HttpRequest | 创建 POST 请求 |
put(String path) | path: 请求路径 | HttpRequest | 创建 PUT 请求 |
delete(String path) | path: 请求路径 | HttpRequest | 创建 DELETE 请求 |
rest(HttpMethod method, String path) | method: HTTP 方法 path: 请求路径 | HttpRequest | 创建通用请求 |
HttpRequest 方法
Section titled “HttpRequest 方法”| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
header(String name, String value) | name: 头名称 value: 头值 | HttpRequest | 设置请求头 |
body(String body) | body: 请求体 | HttpRequest | 设置请求体 |
body(byte[] body) | body: 请求体字节数组 | HttpRequest | 设置请求体 |
onResponseHeader(Consumer<HttpResponse> callback) | callback: 回调函数 | HttpRequest | 响应头回调 |
onResponseBody(Stream callback) | callback: 流式回调 | HttpRequest | 响应体流式回调 |
onSuccess(Consumer<HttpResponse> callback) | callback: 成功回调 | HttpRequest | 请求成功回调 |
onFailure(Consumer<Throwable> callback) | callback: 失败回调 | HttpRequest | 请求失败回调 |
submit() | - | void | 提交请求 |
HttpResponse 方法
Section titled “HttpResponse 方法”| 方法 | 返回值 | 说明 |
|---|---|---|
statusCode() | int | 获取状态码 |
body() | String | 获取响应体 |
getHeader(String name) | String | 获取指定响应头 |
getHeaderNames() | Set<String> | 获取所有响应头名称 |
HttpClient 实例化
Section titled “HttpClient 实例化”HttpClient 提供了两种实例化方式,让你可以根据不同的场景选择最适合的方式。
方式一:完整的请求URL
Section titled “方式一:完整的请求URL”这种方式最为直观,只需要传入完整的 URL 即可:
// HTTP 请求HttpClient client = new HttpClient("http://127.0.0.1:8080");
// HTTPS 请求HttpClient client = new HttpClient("https://smartboot.tech/feat/");HttpClient 会自动解析 URL 中的 host 和 port 信息,并识别是否使用 HTTPS 协议。
方式二:指定 host、port
Section titled “方式二:指定 host、port”如果你更喜欢分别指定主机和端口,也可以这样:
// HTTP 请求HttpClient httpClient = new HttpClient("127.0.0.1", 8080);
// HTTPS 请求HttpClient httpClient = new HttpClient("smartboot.tech", 443);这两种方式各有优势,你可以根据实际需求选择。
通过 HttpClient.options() 方法可以对客户端进行详细配置,支持链式调用。
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
host | String | null | 服务地址,必填项 |
port | int | 80 | 服务端口 |
connectTimeout | int | 0 | 连接超时时间(毫秒),0 表示永不超时 |
readBufferSize | int | 1024 | 读缓冲区大小(字节) |
writeBufferSize | int | 1024 | 写缓冲区大小(字节) |
debug | boolean | false | 是否开启调试模式 |
proxy | ProxyOptions | null | 代理配置 |
HttpClient client = new HttpClient("https://api.example.com");client.options() .connectTimeout(5000) // 5秒超时 .readBufferSize(4096) // 4KB 读缓冲区 .writeBufferSize(4096) // 4KB 写缓冲区 .debug(true); // 开启调试模式HTTP请求
Section titled “HTTP请求”HttpClient 提供了多种方式来发送 HTTP 请求,满足不同的使用场景。
通用请求方法
Section titled “通用请求方法”HttpClient 提供了 rest() 方法用于发送通用的 HTTP 请求:
import tech.smartboot.feat.core.client.HttpClient;import tech.smartboot.feat.core.client.HttpMethod;
public class HttpRestDemo { public static void main(String[] args) { // 创建 HttpClient 实例 HttpClient client = new HttpClient("https://smartboot.tech"); client.options().debug(true);
// 发送 GET 请求 client.rest(HttpMethod.GET, "/feat/").onSuccess(response -> { System.out.println("Status Code: " + response.statusCode()); System.out.println("Body: " + response.body()); }).submit(); }}专用请求方法
Section titled “专用请求方法”对于常见的 HTTP 请求方法,HttpClient 提供了对应的便捷方法:
GET 请求
Section titled “GET 请求”HttpClient httpClient = new HttpClient("https://api.example.com");httpClient.get("/users") .header("Authorization", "Bearer token") .onSuccess(response -> System.out.println(response.body())) .onFailure(Throwable::printStackTrace) .submit();POST 请求
Section titled “POST 请求”HttpClient httpClient = new HttpClient("https://api.example.com");httpClient.post("/users") .header("Content-Type", "application/json") .body("{\"name\": \"张三\", \"age\": 25}") .onSuccess(response -> System.out.println("Status: " + response.statusCode())) .onFailure(Throwable::printStackTrace) .submit();PUT 请求
Section titled “PUT 请求”HttpClient httpClient = new HttpClient("https://api.example.com");httpClient.put("/users/1") .header("Content-Type", "application/json") .body("{\"name\": \"李四\", \"age\": 30}") .onSuccess(response -> System.out.println("Update successful")) .onFailure(Throwable::printStackTrace) .submit();DELETE 请求
Section titled “DELETE 请求”HttpClient httpClient = new HttpClient("https://api.example.com");httpClient.delete("/users/1") .onSuccess(response -> System.out.println("Delete successful")) .onFailure(Throwable::printStackTrace) .submit();HttpClient 提供了强大的异步回调机制,可以在请求发送后立即返回,而不需要等待请求完成。
| 回调方法 | 触发时机 | 用途 |
|---|---|---|
onResponseHeader | 响应 Header 解析完成后 | 检查状态码和头部信息 |
onResponseBody | 接收到 Body 内容时 | 流式处理响应体 |
onSuccess | 请求成功完成时 | 处理完整响应 |
onFailure | 请求失败时 | 处理异常、超时 |
onResponseHeader 示例
Section titled “onResponseHeader 示例”HttpClient httpClient = new HttpClient("https://smartboot.tech");httpClient.get("/feat/") .onResponseHeader(response -> { System.out.println("Status Code: " + response.statusCode()); for (String name : response.getHeaderNames()) { System.out.println(name + ": " + response.getHeader(name)); } }) .submit();onResponseBody 示例
Section titled “onResponseBody 示例”import tech.smartboot.feat.core.client.HttpResponse;import tech.smartboot.feat.core.client.HttpClient.Stream;import java.io.IOException;
public class ResponseBodyDemo { public static void main(String[] args) { HttpClient httpClient = new HttpClient("https://smartboot.tech"); httpClient.get("/feat/") .onResponseBody(new Stream() { @Override public void stream(HttpResponse response, byte[] bytes, boolean end) throws IOException { System.out.println("接收到数据:" + new String(bytes)); if (end) { System.out.println("数据接收完毕"); } } }) .submit(); }}完整回调示例
Section titled “完整回调示例”HttpClient httpClient = new HttpClient("https://api.example.com");httpClient.get("/users") .header("Authorization", "Bearer token") .onResponseHeader(response -> { System.out.println("Status: " + response.statusCode()); }) .onResponseBody((response, bytes, end) -> { System.out.print(new String(bytes)); if (end) { System.out.println("\nResponse complete"); } }) .onSuccess(response -> { System.out.println("Request successful"); }) .onFailure(e -> { System.err.println("Request failed: " + e.getMessage()); e.printStackTrace(); }) .submit();场景 1:调用 RESTful API
Section titled “场景 1:调用 RESTful API”适用条件:需要与 RESTful API 进行通信
示例:
HttpClient client = new HttpClient("https://api.github.com");client.get("/users/octocat") .header("Accept", "application/json") .onSuccess(response -> { System.out.println("GitHub user info: " + response.body()); }) .onFailure(e -> { System.err.println("Failed to get user info: " + e.getMessage()); }) .submit();场景 2:文件上传
Section titled “场景 2:文件上传”适用条件:需要上传文件到服务器
示例:
import java.io.File;import java.io.FileInputStream;import java.io.IOException;
public class FileUploadDemo { public static void main(String[] args) throws IOException { HttpClient client = new HttpClient("http://localhost:8080");
// 读取文件内容 File file = new File("example.txt"); byte[] fileContent = new byte[(int) file.length()]; try (FileInputStream fis = new FileInputStream(file)) { fis.read(fileContent); }
// 发送文件 client.post("/upload") .header("Content-Type", "application/octet-stream") .body(fileContent) .onSuccess(response -> { System.out.println("Upload successful: " + response.body()); }) .onFailure(e -> { System.err.println("Upload failed: " + e.getMessage()); }) .submit(); }}场景 3:微服务间通信
Section titled “场景 3:微服务间通信”适用条件:在微服务架构中,服务之间需要相互调用
示例:
public class ServiceCommunication { private final HttpClient userServiceClient; private final HttpClient orderServiceClient;
public ServiceCommunication() { // 初始化客户端实例(建议单例) this.userServiceClient = new HttpClient("http://user-service:8080"); this.orderServiceClient = new HttpClient("http://order-service:8080");
// 配置超时和缓冲区 userServiceClient.options().connectTimeout(3000); orderServiceClient.options().connectTimeout(3000); }
public void getUserOrders(String userId) { // 先获取用户信息 userServiceClient.get("/users/" + userId) .onSuccess(userResponse -> { System.out.println("User info: " + userResponse.body());
// 再获取用户订单 orderServiceClient.get("/orders?userId=" + userId) .onSuccess(orderResponse -> { System.out.println("User orders: " + orderResponse.body()); }) .onFailure(e -> { System.err.println("Failed to get orders: " + e.getMessage()); }) .submit(); }) .onFailure(e -> { System.err.println("Failed to get user: " + e.getMessage()); }) .submit(); }}在使用 HttpClient 时,有一些最佳实践可以帮助你写出更好的代码:
1. 实例管理
Section titled “1. 实例管理”- 复用 HttpClient 实例:避免频繁创建和销毁客户端实例,建议使用单例模式
- 连接池管理:对于高并发场景,合理配置连接池参数
- 资源释放:不需要时关闭客户端连接
2. 超时设置
Section titled “2. 超时设置”- 合理设置超时时间:避免请求无限期挂起
- 根据网络环境调整:内网服务可以设置较短超时,外网服务设置较长超时
- 示例:
client.options().connectTimeout(5000); // 5秒连接超时
3. 异常处理
Section titled “3. 异常处理”- 全面的异常处理:使用 onFailure 回调处理各种异常情况
- 错误重试机制:对于临时网络问题,实现适当的重试逻辑
- 日志记录:记录请求失败的详细信息,便于排查问题
4. 性能优化
Section titled “4. 性能优化”- 缓冲区大小:根据实际数据大小调整读写缓冲区
- 调试模式:开发阶段开启,生产环境关闭
- 异步处理:充分利用异步回调,避免阻塞主线程
5. 安全实践
Section titled “5. 安全实践”- HTTPS 使用:敏感数据传输使用 HTTPS
- 认证信息保护:避免在代码中硬编码认证信息
- 请求验证:验证服务端响应,防止恶意返回
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 连接超时 | 网络问题或服务不可用 | 检查网络连接,增加超时时间,实现重试机制 |
| 404 Not Found | 请求路径错误 | 检查 API 路径是否正确 |
| 401 Unauthorized | 认证失败 | 检查认证信息是否正确,确保 token 有效 |
| 403 Forbidden | 权限不足 | 检查用户权限,确保有访问资源的权限 |
| 500 Internal Server Error | 服务端错误 | 检查服务端日志,联系服务提供者 |
| 连接被拒绝 | 服务未启动或端口错误 | 确认服务是否运行,检查端口配置 |
| SSL 握手失败 | 证书问题 | 检查证书是否有效,是否添加到信任库 |
-
开启调试模式:
client.options().debug(true); -
检查网络连接:
- 使用
ping命令检查目标服务器是否可达 - 使用
curl命令测试 API 是否正常
- 使用
-
查看详细错误信息:
.onFailure(e -> {System.err.println("Error: " + e.getMessage());e.printStackTrace();})
import tech.smartboot.feat.core.client.HttpClient;import tech.smartboot.feat.core.client.HttpResponse;import tech.smartboot.feat.core.client.HttpClient.Stream;import java.io.IOException;
public class HttpClientCompleteDemo { public static void main(String[] args) { // 创建 HttpClient 实例 HttpClient client = new HttpClient("https://api.example.com");
// 配置客户端 client.options() .connectTimeout(5000) .readBufferSize(4096) .writeBufferSize(4096) .debug(true);
// 发送 POST 请求 client.post("/api/users") .header("Content-Type", "application/json") .header("Authorization", "Bearer your-token-here") .body("{\"name\": \"张三\", \"email\": \"zhangsan@example.com\"}") .onResponseHeader(response -> { System.out.println("Status Code: " + response.statusCode()); System.out.println("Content-Type: " + response.getHeader("Content-Type")); }) .onResponseBody(new Stream() { @Override public void stream(HttpResponse response, byte[] bytes, boolean end) throws IOException { System.out.print(new String(bytes)); if (end) { System.out.println("\nResponse completed"); } } }) .onSuccess(response -> { System.out.println("\nRequest successful!"); System.out.println("Response body: " + response.body()); }) .onFailure(e -> { System.err.println("\nRequest failed:"); e.printStackTrace(); }) .submit();
// 注意:由于是异步请求,主线程需要等待 try { Thread.sleep(10000); // 等待 10 秒让请求完成 } catch (InterruptedException e) { e.printStackTrace(); } }}- SSE Client:处理服务器发送事件
- WebSocket Client:实现双向实时通信
- Feat 服务器:构建 HTTP 服务器
- Feat Cloud:构建 Web 应用