跳转到内容

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>

万事开头难,让我们从一个简单的例子开始。下面的示例展示了如何使用 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 的各种功能。


方法参数返回值说明
HttpClient(String url)url: 完整的请求 URLHttpClient创建 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创建通用请求
方法参数返回值说明
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提交请求
方法返回值说明
statusCode()int获取状态码
body()String获取响应体
getHeader(String name)String获取指定响应头
getHeaderNames()Set<String>获取所有响应头名称

HttpClient 提供了两种实例化方式,让你可以根据不同的场景选择最适合的方式。

这种方式最为直观,只需要传入完整的 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 协议。

如果你更喜欢分别指定主机和端口,也可以这样:

// HTTP 请求
HttpClient httpClient = new HttpClient("127.0.0.1", 8080);
// HTTPS 请求
HttpClient httpClient = new HttpClient("smartboot.tech", 443);

这两种方式各有优势,你可以根据实际需求选择。


通过 HttpClient.options() 方法可以对客户端进行详细配置,支持链式调用。

配置项类型默认值说明
hostStringnull服务地址,必填项
portint80服务端口
connectTimeoutint0连接超时时间(毫秒),0 表示永不超时
readBufferSizeint1024读缓冲区大小(字节)
writeBufferSizeint1024写缓冲区大小(字节)
debugbooleanfalse是否开启调试模式
proxyProxyOptionsnull代理配置
HttpClient client = new HttpClient("https://api.example.com");
client.options()
.connectTimeout(5000) // 5秒超时
.readBufferSize(4096) // 4KB 读缓冲区
.writeBufferSize(4096) // 4KB 写缓冲区
.debug(true); // 开启调试模式

HttpClient 提供了多种方式来发送 HTTP 请求,满足不同的使用场景。

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();
}
}

对于常见的 HTTP 请求方法,HttpClient 提供了对应的便捷方法:

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();
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();
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();
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请求失败时处理异常、超时
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();
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();
}
}
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();

适用条件:需要与 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();

适用条件:需要上传文件到服务器

示例

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();
}
}

适用条件:在微服务架构中,服务之间需要相互调用

示例

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 时,有一些最佳实践可以帮助你写出更好的代码:

  • 复用 HttpClient 实例:避免频繁创建和销毁客户端实例,建议使用单例模式
  • 连接池管理:对于高并发场景,合理配置连接池参数
  • 资源释放:不需要时关闭客户端连接
  • 合理设置超时时间:避免请求无限期挂起
  • 根据网络环境调整:内网服务可以设置较短超时,外网服务设置较长超时
  • 示例
    client.options().connectTimeout(5000); // 5秒连接超时
  • 全面的异常处理:使用 onFailure 回调处理各种异常情况
  • 错误重试机制:对于临时网络问题,实现适当的重试逻辑
  • 日志记录:记录请求失败的详细信息,便于排查问题
  • 缓冲区大小:根据实际数据大小调整读写缓冲区
  • 调试模式:开发阶段开启,生产环境关闭
  • 异步处理:充分利用异步回调,避免阻塞主线程
  • HTTPS 使用:敏感数据传输使用 HTTPS
  • 认证信息保护:避免在代码中硬编码认证信息
  • 请求验证:验证服务端响应,防止恶意返回

问题可能原因解决方案
连接超时网络问题或服务不可用检查网络连接,增加超时时间,实现重试机制
404 Not Found请求路径错误检查 API 路径是否正确
401 Unauthorized认证失败检查认证信息是否正确,确保 token 有效
403 Forbidden权限不足检查用户权限,确保有访问资源的权限
500 Internal Server Error服务端错误检查服务端日志,联系服务提供者
连接被拒绝服务未启动或端口错误确认服务是否运行,检查端口配置
SSL 握手失败证书问题检查证书是否有效,是否添加到信任库
  1. 开启调试模式

    client.options().debug(true);
  2. 检查网络连接

    • 使用 ping 命令检查目标服务器是否可达
    • 使用 curl 命令测试 API 是否正常
  3. 查看详细错误信息

    .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();
}
}
}