Ce face HttpClient.sendAsync
sendAsync este varianta asincronă a lui send: pornește cererea și revine imediat cu un CompletableFuture<HttpResponse<T>>. Poți continua lanțul (thenApply(HttpResponse::body)) și poți trimite mai multe cereri în paralel.
Pentru a aștepta toate cererile folosești CompletableFuture.allOf sau join() pe fiecare. Erorile de rețea nu se aruncă direct, ci ajung în future: le tratezi cu exceptionally sau le primești ca CompletionException la join().
Parametri
| Parametru | Descriere |
|---|---|
cerere |
Cererea de trimis. |
handler |
Cum se citește corpul răspunsului. |
Ce returnează
Un CompletableFuture<HttpResponse<T>>.
Exemple
Exemplul 1: Trei cereri în paralel
Serverul răspunde la fiecare oraș după 300 ms. Cererile pornesc toate odată, deci așteptarea totală este de aproximativ 300 ms, nu 900 ms. Rezultatele se citesc în ordinea listei, deci afișarea este mereu aceeași.
import com.sun.net.httpserver.HttpServer;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) throws Exception {
HttpServer server = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 0);
server.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
server.createContext("/vreme", schimb -> {
String oras = schimb.getRequestURI().getQuery();
try {
Thread.sleep(300);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
byte[] corp = (oras + ": " + (oras.length() + 8) + "°C").getBytes(StandardCharsets.UTF_8);
schimb.sendResponseHeaders(200, corp.length);
try (OutputStream out = schimb.getResponseBody()) {
out.write(corp);
}
});
server.start();
String baza = "http://127.0.0.1:" + server.getAddress().getPort() + "/vreme?";
try (HttpClient client = HttpClient.newHttpClient()) {
List<CompletableFuture<String>> cereri = List.of("Iași", "Cluj", "Constanța").stream()
.map(oras -> HttpRequest.newBuilder(URI.create(baza + URLEncoder.encode(oras, StandardCharsets.UTF_8))).build())
.map(cerere -> client.sendAsync(cerere, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body))
.toList();
cereri.forEach(c -> System.out.println(c.join()));
}
server.stop(0);
}
}
Rezultat
Iași: 12°C
Cluj: 12°C
Constanța: 17°C
Exemplul 2: Eroare de rețea tratată cu exceptionally
Pe portul 9 (discard) nu ascultă nimeni, deci conectarea eșuează.
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Main {
public static void main(String[] args) {
try (HttpClient client = HttpClient.newHttpClient()) {
HttpRequest cerere = HttpRequest.newBuilder(URI.create("http://127.0.0.1:9/")).build();
String rezultat = client.sendAsync(cerere, HttpResponse.BodyHandlers.ofString())
.thenApply(r -> "Stare " + r.statusCode())
.exceptionally(e -> "Cererea a eșuat: " + e.getCause().getClass().getSimpleName())
.join();
System.out.println(rezultat);
}
}
}
Rezultat
Cererea a eșuat: ConnectException
Greșeli frecvente
- Apelezi
sendAsync(...).join()imediat, pentru fiecare cerere, într-o buclă. Cererile rulează una după alta; trimite-le întâi pe toate. - Uiți să aștepți future-urile înainte de sfârșitul lui
main. Programul se poate opri înainte să sosească răspunsurile.
Comenzi înrudite
HttpClient.send: Trimite o cerere HTTP și așteaptă răspunsul; BodyHandlers.ofString() citește corpul ca text.CompletableFuture.thenApply: thenApply transformă rezultatul când este gata (ca map); thenAccept îl folosește fără să returneze ceva (ca forEach).CompletableFuture.allOf: Returnează un CompletableFuture care se termină când s-au terminat toate cele primite; anyOf, când s-a terminat primul.HttpClient: Clientul HTTP din Java 11: newHttpClient() îl creează, send/sendAsync trimit cereri și primesc răspunsuri.