发送请求后如何编辑方法?以及如何在每个CompletableFuture发送前修改请求参数?
问题描述
我需要从某网站获取四个数值,但每一步都需要修改请求参数。原本打算用Executor来实现,但未能成功。请问如何在每个CompletableFuture发送请求前修改参数?以下是我的代码实现:
HttpRequest httpRequest = HttpRequest.newBuilder() .version(Version.HTTP_1_1) .uri(URI.create(sourceUrl)) .header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8") .method("POST", BodyPublishers.ofFile(Paths.get("Resources/Payload.txt"))) .build(); ExecutorService executorService = Executors.newFixedThreadPool(4); HttpClient httpClient = HttpClient.newBuilder() .executor(executorService) .connectTimeout(Duration.ofSeconds(10)) .build(); CompletableFuture<HttpResponse<String>> a = httpClient.sendAsync(httpRequest, BodyHandlers.ofString()); CompletableFuture<HttpResponse<String>> b = httpClient.sendAsync(httpRequest, BodyHandlers.ofString()); CompletableFuture<HttpResponse<String>> c = httpClient.sendAsync(httpRequest, BodyHandlers.ofString()); CompletableFuture<HttpResponse<String>> d = httpClient.sendAsync(httpRequest, BodyHandlers.ofString());
解决方案
你现在的问题在于所有请求都复用了同一个HttpRequest实例,而HttpRequest是不可变对象(immutable),一旦build之后就没法修改参数了。所以要给每个异步请求创建独立的、带有不同参数的HttpRequest才行,下面给你两种实用的实现方式:
方式一:为每个请求单独构建HttpRequest
既然每个请求参数不同,那我们可以写个工具方法来生成不同的请求,比如假设你需要修改的是请求体或者某个Header参数:
// 定义一个生成带指定参数的HttpRequest的方法 private static HttpRequest buildRequest(String sourceUrl, String customPayloadPath) throws IOException { return HttpRequest.newBuilder() .version(HttpRequest.Version.HTTP_1_1) .uri(URI.create(sourceUrl)) .header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8") // 这里根据传入的参数修改请求体,你也可以修改Header、URI等其他参数 .method("POST", HttpRequest.BodyPublishers.ofFile(Paths.get(customPayloadPath))) .build(); } // 然后在创建CompletableFuture时分别调用这个方法 ExecutorService executorService = Executors.newFixedThreadPool(4); HttpClient httpClient = HttpClient.newBuilder() .executor(executorService) .connectTimeout(Duration.ofSeconds(10)) .build(); // 四个不同参数的请求,这里假设每个请求用不同的Payload文件 CompletableFuture<HttpResponse<String>> a = httpClient.sendAsync(buildRequest(sourceUrl, "Resources/PayloadA.txt"), HttpResponse.BodyHandlers.ofString()); CompletableFuture<HttpResponse<String>> b = httpClient.sendAsync(buildRequest(sourceUrl, "Resources/PayloadB.txt"), HttpResponse.BodyHandlers.ofString()); CompletableFuture<HttpResponse<String>> c = httpClient.sendAsync(buildRequest(sourceUrl, "Resources/PayloadC.txt"), HttpResponse.BodyHandlers.ofString()); CompletableFuture<HttpResponse<String>> d = httpClient.sendAsync(buildRequest(sourceUrl, "Resources/PayloadD.txt"), HttpResponse.BodyHandlers.ofString());
方式二:用CompletableFuture.supplyAsync结合自定义逻辑
如果你希望更灵活地控制参数修改的逻辑(比如在异步线程里动态生成参数),可以用supplyAsync来包裹请求逻辑,这样每个异步任务都会独立生成请求:
ExecutorService executorService = Executors.newFixedThreadPool(4); HttpClient httpClient = HttpClient.newBuilder() .connectTimeout(Duration.ofSeconds(10)) .build(); // 每个supplyAsync都会在executor的线程里执行,生成各自的请求并发送 CompletableFuture<HttpResponse<String>> a = CompletableFuture.supplyAsync(() -> { try { // 在这里动态修改参数,比如生成不同的请求体 HttpRequest request = HttpRequest.newBuilder() .version(HttpRequest.Version.HTTP_1_1) .uri(URI.create(sourceUrl)) .header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8") .method("POST", HttpRequest.BodyPublishers.ofString("param1=valueA")) // 自定义参数A .build(); return httpClient.send(request, HttpResponse.BodyHandlers.ofString()); } catch (IOException | InterruptedException e) { throw new CompletionException(e); } }, executorService); CompletableFuture<HttpResponse<String>> b = CompletableFuture.supplyAsync(() -> { try { HttpRequest request = HttpRequest.newBuilder() .version(HttpRequest.Version.HTTP_1_1) .uri(URI.create(sourceUrl)) .header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8") .method("POST", HttpRequest.BodyPublishers.ofString("param1=valueB")) // 自定义参数B .build(); return httpClient.send(request, HttpResponse.BodyHandlers.ofString()); } catch (IOException | InterruptedException e) { throw new CompletionException(e); } }, executorService); // 同理创建c和d的CompletableFuture
关键优化提示
如果你的参数修改逻辑重复,可以把参数封装成一个列表,用循环批量生成所有的CompletableFuture,代码会更简洁:
List<String> payloadValues = List.of("valueA", "valueB", "valueC", "valueD"); List<CompletableFuture<HttpResponse<String>>> futures = payloadValues.stream() .map(payload -> CompletableFuture.supplyAsync(() -> { try { HttpRequest request = HttpRequest.newBuilder() .version(HttpRequest.Version.HTTP_1_1) .uri(URI.create(sourceUrl)) .header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8") .method("POST", HttpRequest.BodyPublishers.ofString("param=" + payload)) .build(); return httpClient.send(request, HttpResponse.BodyHandlers.ofString()); } catch (IOException | InterruptedException e) { throw new CompletionException(e); } }, executorService)) .collect(Collectors.toList()); // 等待所有请求完成 CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
内容的提问来源于stack exchange,提问作者hirtevurte
相关产品推荐
相关产品推荐

