java - Java 发送多个 HTTP 请求的最佳方式
问题描述
我有一个 Java 程序,它使用 Java 11 HttpClient 向服务器发送数百个 GET 请求,它需要每分钟执行 2-3 次。目前,它执行以下操作(仅描述逻辑):
for each request that needs to be sent:
//build GET request
CompletableFuture<HttpResponse<String>> future = client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
futures.add(future)
// for every 100 request, sleep for 2500 milliseconds (to wait for responses)
for each future in futures:
// parse JSON response
该代码大部分工作正常,但是,它受到互联网连接强度的严重影响,好像它很糟糕,80%的请求没有得到他们的响应,因为等待时间不够。
问题是这是否是正确的方法,如果不是,它会是什么。另外,我是否应该等待所有请求得到响应(例如同步发送请求并使用 .join()),如果是,我该怎么做。
解决方案
如果您所有的 API 调用都是独立的,那么您可以先触发,然后您可以稍后加入结果。
使用 GET 的简单示例:
List<URI> uris = ... //
HttpClient client = HttpClient.newHttpClient();
List<HttpRequest> requests = uris.stream()
.map(HttpRequest::newBuilder)
.map(reqBuilder -> reqBuilder.build())
.collect(toList());
CompletableFuture.allOf(requests.stream()
.map(request -> client.sendAsync(request, ofString()))
.toArray(CompletableFuture<?>[]::new))
.join();
您也可以从使用自定义执行器中受益:
private static final ExecutorService executorService = Executors.newFixedThreadPool(5);
private static final HttpClient httpClient = HttpClient.newBuilder()
.executor(executorService)
.version(HttpClient.Version.HTTP_2)
.connectTimeout(Duration.ofSeconds(10))
.build();
已编辑----
如果你想要结果,那么 allOf 没有帮助,因为它实际上返回了一个 VOID。
静态 CompletableFuture allOf(CompletableFuture<?>...cfs)
当所有给定的 CompletableFuture 完成时,返回一个新的 CompletableFuture。
相反,您仍然可以使用 join,但是以不同的方式:
List<CompleteFuture<HttpResponse<String>> listOfCompletableFutures = ...
listOfCompletableFutures.
.stream()
.map(CompletableFuture::join)
.filter(Objects::nonNull)
.collect(Collectors.toList());
好的参考资料:
https://openjdk.java.net/groups/net/httpclient/recipes.html
Java 11 HttpClient - HttpClients 与并发 HttpRequests 的最佳比率是多少
推荐阅读
- bash - Bash sed awk,从 /proc/cpuinfo 和 /proc/meminfo 格式化 CPU/Mem 信息
- c# - SqlException (0x80131904): 无法打开备份设备操作系统错误5(拒绝访问。)
- c++ - 在 C++ 中将连续范围映射到离散箱中
- excel - EXCEL:如果column_A中的单元格包含column_C中的单词,则将单词插入它旁边(来自column_D)INTO B
- angular - TypeError:无法读取茉莉花中未定义的属性“客户端”
- spring-boot - 对多个消息使用者使用手动提交
- html - 如何使用 Vue draggable 将组件列表中的项目拖动到另一个组件中的列表?
- ios - 请求的身份验证范围不足 Google Sheets API Swift
- flutter - Flutter 在网格视图中增加容器高度
- typescript - 类型“字符串”不可分配给类型“ImageSourcePropType”