Java 11 HttpClient 发最简GET请求需用HttpClient.newBuilder().build()创建客户端,HttpRequest.newBuilder(URI).GET().build()构建请求,并必须指定HttpResponse.BodyHandlers.ofString()处理响应体,再调用send()同步执行。

Java 11 HttpClient 怎么发一个最简 GET 请求
不用第三方库,Java 11 自带的 HttpClient 就能发请求,但写法和 Apache HttpClient 或 OkHttp 完全不同——它默认是异步非阻塞的,同步调用反而要显式等结果。
常见错误:直接 new HttpClient() 报错,因为构造器私有;或者漏掉 HttpResponse.BodyHandlers.ofString() 导致编译不通过。
-
HttpClient必须用HttpClient.newBuilder().build()创建 - GET 请求必须链式调用
HttpRequest.newBuilder(URI).GET().build() - 响应体处理器不能省,
BodyHandlers.ofString()返回String,ofByteArray()更适合二进制 - 同步执行用
client.send(request, handler);异步用client.sendAsync(request, handler).join()(注意join()才真正取值)
示例(同步):
var client = HttpClient.newBuilder().build();
var request = HttpRequest.newBuilder(URI.create("https://httpbin.org/get")).GET().build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
为什么 sendAsync 不立刻返回响应体,而要 .join() 或 .thenApply()
因为 sendAsync() 返回的是 CompletableFuture,不是结果本身。这是 Java 的标准异步抽象,不是 HttpClient 特有设计,但新手常误以为“异步=自动执行完”。
容易踩的坑:只调 sendAsync() 就结束,主线程退出,Future 还没完成,结果丢失;或在 Servlet 环境里用 join() 阻塞线程,拖垮吞吐量。
立即学习“Java免费学习笔记(深入)”;
- 测试/命令行场景可用
.join()简单等待 - Web 应用中应链式用
.thenApply(r -> r.body())+.thenAccept(System.out::println),避免阻塞 -
CompletableFuture默认用 ForkJoinPool.commonPool(),高并发下可能需自定义线程池(通过executor()方法传入)
POST JSON 数据时 Content-Type 和 body 怎么配才不 400
400 Bad Request 多半是服务端没收到合法 JSON,根源常在两处:没设 Content-Type: application/json,或 body 没正确序列化为字节流。
Java 11 的 HttpRequest 不自动处理 JSON,也无内置序列化——你得自己转 String 再转 byte[],且必须指定 UTF-8 编码。
- 用
HttpRequest.BodyPublishers.ofString(jsonStr, StandardCharsets.UTF_8),别用无参版本(默认 ISO-8859-1) -
Header必须显式加:header("Content-Type", "application/json") - 如果 JSON 含中文,UTF-8 编码缺失会导致服务端解析失败,错误日志可能只显示“invalid JSON”
- 大 JSON 建议用
ofInputStream()配合BufferedInputStream,避免内存峰值
示例:
String json = "{\"name\":\"Alice\"}";
var request = HttpRequest.newBuilder(URI.create("https://httpbin.org/post"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json, StandardCharsets.UTF_8))
.build();
连接超时、读超时、重试这些怎么配
HttpClient 把超时拆得很细:连接建立超时(connect timeout)靠 connectTimeout(),但读超时(read timeout)没有独立 API——它由整个 send() 或 sendAsync() 调用的执行时间决定,需靠 CompletableFuture.orTimeout() 补齐。
重试完全不内置,得自己套逻辑。官方有意保持轻量,把策略交给上层。
- 连接超时:用
HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(5)) - 读超时:对异步调用,加
.orTimeout(10, TimeUnit.SECONDS);同步调用只能靠Thread.interrupt()配合自定义 handler(不推荐) - 重试:用
CompletableFuture的handle()捕获IOException,再递归调用或循环重试,注意控制次数和退避(如delay) - HTTP 状态码重试(如 503)需手动检查
response.statusCode(),HttpClient不做语义重试
复杂点在于:超时和重试逻辑一旦嵌套,容易泄漏连接或重复提交。实际项目中,建议把重试+超时封装成工具方法,而不是每次手写。









