Java如何实现并行HTTP GET请求并将多请求结果合并为JSONObject
优化实现思路
- 替换同步HTTP客户端为异步版本:你当前用的是同步Apache HttpClient,每个请求都会阻塞等待返回,60个请求的耗时是所有请求耗时的累加值。可以改用支持异步的HTTP客户端,比如Java 11+内置的
HttpClient、OkHttp或者Apache Async HttpClient,异步请求不会阻塞当前线程,可同时发起多个请求,总耗时近似于单个请求的最长耗时。 - 用
CompletableFuture管理批量异步任务:拿到总页数后,把每个页码的请求都封装成独立的CompletableFuture异步任务,全部提交后调用CompletableFuture.allOf()等待所有任务执行完成,再统一把结果汇总到JSONObject中,不需要循环逐个等待请求返回。 - 抽离公共请求逻辑:把重复的HTTP请求、响应解析逻辑抽成单独的工具方法,入参为页码,出参为对应页的
JSONArray,不用复制粘贴多份代码,后续修改请求配置也只需调整一处。 - 控制并发量级:不要一次性发起全部60个请求,可将并发数控制在10~20之间,避免触发目标API的限流规则导致请求失败,可以通过自定义线程池的核心线程数,或者用
Semaphore信号量实现并发数管控。
学习指引
- 先掌握Java并发基础组件:重点学习线程池、
CompletableFuture的常用API,不需要一开始深入底层原理,先能跑通基础的异步任务、多任务合并等待逻辑即可。 - 再学习异步HTTP客户端的基础用法:选择一款异步HTTP客户端,从单个异步GET请求的示例开始跑通,再扩展到批量请求的场景。
- 最后补充异常处理逻辑:给请求增加超时配置、失败重试、异常捕获逻辑,避免单个页请求失败导致整个数据拉取任务崩溃。
简化优化示例代码(基于Java 11+ 内置HttpClient)
import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; import org.json.JSONArray; import org.json.JSONObject; public class PageFetcher { private static final String BASE = "https://someapi.com/api?page="; // 全局复用HttpClient,不用每次请求新建 private static final HttpClient HTTP_CLIENT = HttpClient.newHttpClient(); // 抽离单页请求逻辑 private static CompletableFuture<JSONArray> getPageData(int page) { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(BASE + page)) .timeout(java.time.Duration.ofSeconds(10)) // 配置10秒超时 .build(); // 异步发送请求,解析返回结果 return HTTP_CLIENT.sendAsync(request, HttpResponse.BodyHandlers.ofString()) .thenApply(response -> new JSONObject(response.body()).getJSONArray("data")); } public static String getData() throws Exception { JSONObject finalData = new JSONObject(); // 先同步拉取第一页拿到总页数 HttpRequest firstPageReq = HttpRequest.newBuilder() .uri(URI.create(BASE + 0)) .timeout(java.time.Duration.ofSeconds(10)) .build(); HttpResponse<String> firstResp = HTTP_CLIENT.send(firstPageReq, HttpResponse.BodyHandlers.ofString()); JSONObject firstJson = new JSONObject(firstResp.body()); int pages = firstJson.getInt("totalPages"); finalData.put("0", firstJson.getJSONArray("data")); // 提交剩余页的异步请求 List<CompletableFuture<Void>> taskList = new ArrayList<>(); for (int x = 1; x < pages; x++) { int pageNum = x; CompletableFuture<Void> task = getPageData(pageNum) .thenAccept(data -> finalData.put(String.valueOf(pageNum), data)); taskList.add(task); } // 等待所有异步请求完成 CompletableFuture.allOf(taskList.toArray(new CompletableFuture[0])).join(); return finalData.toString(); } }
内容的提问来源于stack exchange,提问作者nicholxs
相关产品推荐
相关产品推荐

