Streaming¶
Contents | Previous: Authentication, TLS, and Proxy | Next: Client and Request Lifecycle
View in another language — C++ · C#/.NET · Java · Kotlin · Node/TypeScript
After reading this chapter
This chapter processes a response in chunks and sends a request body in parts. Its code comes from each language's HttpClient tutorial.
Streaming moves a large body through a caller callback or provider. Unlike a JSON body, it does not serialize or accumulate the whole body. Response Rules covers status and compression rules.
The provider and sink are each consumed once while the body moves. This is why the streaming path does not apply replay or transparent decompression.
1. Response Chunks Flow Through a Download Sink¶
A download sink is a callback invoked for each received body chunk. A raw response carries status, headers, and the body before JSON decoding. The final raw response from a download preserves status and headers; bodies from intermediate redirect responses do not reach the sink.
AtomicInteger chunks = new AtomicInteger();
AtomicInteger bytes = new AtomicInteger();
client.get("/rooms/" + roomId + "/export")
.download(
chunk -> {
chunks.incrementAndGet();
bytes.addAndGet(chunk.length);
})
.toCompletableFuture()
.join();
System.out.println("download stream: chunks " + chunks.get() + " bytes " + bytes.get());
The example counts each export-body chunk and accumulates the total number of chunks and bytes.
2. Request Chunks Come from a Body Stream Provider¶
A body stream provider returns the next chunk to send and signals completion with the language's empty value. Its configuration includes the content type.
byte[][] lines = {
"{\"playerId\":\"p2\",\"text\":\"import-1\"}\n".getBytes(StandardCharsets.UTF_8),
"{\"playerId\":\"p2\",\"text\":\"import-2\"}\n".getBytes(StandardCharsets.UTF_8),
"{\"playerId\":\"p2\",\"text\":\"import-3\"}\n".getBytes(StandardCharsets.UTF_8),
};
AtomicInteger nextLine = new AtomicInteger();
HttpResponse<Imported> imported =
client.post("/rooms/" + roomId + "/import")
.bodyStream(
() -> {
int index = nextLine.getAndIncrement();
return index < lines.length ? lines[index] : null;
},
"application/x-ndjson")
.submit(Imported.class)
.toCompletableFuture()
.join();
System.out.println("upload stream: imported " + imported.body().imported());
The example supplies three NDJSON lines in sequence and confirms that the server imported three items.
3. Retry and Decompression Are Excluded¶
A download sink and a body stream provider consume their body once and cannot recreate it. A streaming request is therefore excluded from retry and redirect replay. A download sink receives compressed response bytes unchanged; decompression is not applied.
4. Next Chapter¶
Client and Request Lifecycle covers client reuse, close timing, response completion, and timeout boundaries.