17.2 Requests and Responses
Master building and handling HTTP requests and responses.
Building Requests
HttpRequest Builder:
import java.net.http.*;
import java.net.URI;
import java.nio.file.Path;
import java.time.Duration;
/**
* Comprehensive request building
*/
public class RequestBuilder {
/**
* Simple GET request
*/
public static HttpRequest simpleGet(String url) {
return HttpRequest.newBuilder(URI.create(url))
.GET()
.build();
}
/**
* GET with custom headers
*/
public static HttpRequest getWithHeaders(String url,
String... headers) {
HttpRequest.Builder builder = HttpRequest.newBuilder(URI.create(url));
// Headers come in pairs: name, value, name, value, ...
for (int i = 0; i < headers.length; i += 2) {
builder.header(headers[i], headers[i + 1]);
}
return builder.GET().build();
}
/**
* POST with string body
*/
public static HttpRequest postWithString(String url, String body) {
return HttpRequest.newBuilder(URI.create(url))
.POST(HttpRequest.BodyPublishers.ofString(body))
.header("Content-Type", "text/plain")
.build();
}
/**
* POST with JSON body
*/
public static HttpRequest postJSON(String url, String jsonBody) {
return HttpRequest.newBuilder(URI.create(url))
.POST(HttpRequest.BodyPublishers.ofString(jsonBody))
.header("Content-Type", "application/json")
.build();
}
/**
* PUT request
*/
public static HttpRequest putRequest(String url, String body) {
return HttpRequest.newBuilder(URI.create(url))
.PUT(HttpRequest.BodyPublishers.ofString(body))
.header("Content-Type", "application/json")
.build();
}
/**
* DELETE request
*/
public static HttpRequest deleteRequest(String url) {
return HttpRequest.newBuilder(URI.create(url))
.DELETE()
.build();
}
/**
* PATCH request (custom method)
*/
public static HttpRequest patchRequest(String url, String body) {
return HttpRequest.newBuilder(URI.create(url))
.method("PATCH", HttpRequest.BodyPublishers.ofString(body))
.header("Content-Type", "application/json")
.build();
}
}
Request Headers
Advanced Header Management:
/**
* Working with request headers
*/
public class RequestHeaders {
/**
* Common headers
*/
public static HttpRequest buildRequestWithCommonHeaders(String url) {
return HttpRequest.newBuilder(URI.create(url))
.header("Accept", "application/json")
.header("Accept-Language", "en-US")
.header("User-Agent", "MyApp/1.0")
.header("Cache-Control", "no-cache")
.GET()
.build();
}
/**
* Authorization headers
*/
public static HttpRequest withBasicAuth(String url,
String username,
String password) {
String credentials = username + ":" + password;
String encoded = Base64.getEncoder().encodeToString(
credentials.getBytes(StandardCharsets.UTF_8));
return HttpRequest.newBuilder(URI.create(url))
.header("Authorization", "Basic " + encoded)
.GET()
.build();
}
/**
* Bearer token
*/
public static HttpRequest withBearerToken(String url, String token) {
return HttpRequest.newBuilder(URI.create(url))
.header("Authorization", "Bearer " + token)
.GET()
.build();
}
/**
* Custom headers
*/
public static HttpRequest withCustomHeaders(String url,
Map<String, String> headers) {
HttpRequest.Builder builder = HttpRequest.newBuilder(URI.create(url));
headers.forEach(builder::header);
return builder.GET().build();
}
/**
* Accept-Encoding for compression
*/
public static HttpRequest withCompression(String url) {
return HttpRequest.newBuilder(URI.create(url))
.header("Accept-Encoding", "gzip, deflate")
.GET()
.build();
}
}
Request Body Publishers
BodyPublisher Types:
/**
* Different body publisher patterns
*/
public class BodyPublishers {
/**
* String body
*/
public static void stringBody(String url, String content) throws Exception {
HttpRequest request = HttpRequest.newBuilder(URI.create(url))
.POST(HttpRequest.BodyPublishers.ofString(content))
.build();
HttpClient client = HttpClient.newHttpClient();
client.send(request, HttpResponse.BodyHandlers.ofString());
}
/**
* Byte array body
*/
public static void byteArrayBody(String url, byte[] content) throws Exception {
HttpRequest request = HttpRequest.newBuilder(URI.create(url))
.POST(HttpRequest.BodyPublishers.ofByteArray(content))
.build();
HttpClient client = HttpClient.newHttpClient();
client.send(request, HttpResponse.BodyHandlers.ofString());
}
/**
* File body
*/
public static void fileBody(String url, Path filePath) throws Exception {
HttpRequest request = HttpRequest.newBuilder(URI.create(url))
.POST(HttpRequest.BodyPublishers.ofFile(filePath))
.header("Content-Type", "application/octet-stream")
.build();
HttpClient client = HttpClient.newHttpClient();
client.send(request, HttpResponse.BodyHandlers.ofString());
}
/**
* Input stream body
*/
public static void inputStreamBody(String url, InputStream input)
throws Exception {
HttpRequest request = HttpRequest.newBuilder(URI.create(url))
.POST(HttpRequest.BodyPublishers.ofInputStream(() -> input))
.build();
HttpClient client = HttpClient.newHttpClient();
client.send(request, HttpResponse.BodyHandlers.ofString());
}
/**
* Empty body (for GET, DELETE)
*/
public static HttpRequest noBody(String url) {
return HttpRequest.newBuilder(URI.create(url))
.GET()
.build();
}
/**
* Form data
*/
public static HttpRequest formData(String url,
Map<String, String> fields) {
StringBuilder body = new StringBuilder();
fields.forEach((key, value) -> {
if (body.length() > 0) {
body.append("&");
}
try {
body.append(URLEncoder.encode(key, StandardCharsets.UTF_8))
.append("=")
.append(URLEncoder.encode(value, StandardCharsets.UTF_8));
} catch (Exception e) {
// Handle encoding error
}
});
return HttpRequest.newBuilder(URI.create(url))
.POST(HttpRequest.BodyPublishers.ofString(body.toString()))
.header("Content-Type", "application/x-www-form-urlencoded")
.build();
}
}
Response Handlers
BodyHandler Types:
/**
* Different response body handlers
*/
public class ResponseBodyHandlers {
/**
* String response
*/
public static String handleString(String url) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create(url))
.GET()
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
return response.body();
}
/**
* Byte array response
*/
public static byte[] handleByteArray(String url) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create(url))
.GET()
.build();
HttpResponse<byte[]> response = client.send(request,
HttpResponse.BodyHandlers.ofByteArray());
return response.body();
}
/**
* File response
*/
public static Path handleFile(String url, Path targetFile) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create(url))
.GET()
.build();
HttpResponse<Path> response = client.send(request,
HttpResponse.BodyHandlers.ofFile(targetFile));
return response.body();
}
/**
* InputStream response
*/
public static InputStream handleInputStream(String url) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create(url))
.GET()
.build();
HttpResponse<InputStream> response = client.send(request,
HttpResponse.BodyHandlers.ofInputStream());
return response.body();
}
/**
* Discarding response
*/
public static void handleDiscarding(String url) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create(url))
.GET()
.build();
HttpResponse<Void> response = client.send(request,
HttpResponse.BodyHandlers.discarding());
System.out.println("Status: " + response.statusCode());
}
/**
* Custom body handler
*/
public static List<String> customLineHandler(String url) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create(url))
.GET()
.build();
HttpResponse<List<String>> response = client.send(request,
HttpResponse.BodyHandlers.ofLines()
.mapping(line -> line.trim())
.collect(Collectors.toList()));
return response.body();
}
}
Streaming Responses
Large Response Handling:
/**
* Stream large responses efficiently
*/
public class StreamingResponses {
/**
* Stream lines from response
*/
public static void streamLines(String url) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create(url))
.GET()
.build();
HttpResponse<Stream<String>> response = client.send(request,
HttpResponse.BodyHandlers.ofLines());
try (Stream<String> lines = response.body()) {
lines.filter(line -> !line.isEmpty())
.forEach(System.out::println);
}
}
/**
* Process large file
*/
public static long processLargeFile(String url, Path outputFile)
throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create(url))
.GET()
.build();
// Stream to file
HttpResponse<Path> response = client.send(request,
HttpResponse.BodyHandlers.ofFile(outputFile));
return Files.size(response.body());
}
/**
* Streaming with input stream
*/
public static int processInputStream(String url) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create(url))
.GET()
.build();
HttpResponse<InputStream> response = client.send(request,
HttpResponse.BodyHandlers.ofInputStream());
int lineCount = 0;
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(response.body()))) {
String line;
while ((line = reader.readLine()) != null) {
lineCount++;
// Process line
}
}
return lineCount;
}
}
Content Negotiation
Content Type Handling:
/**
* Handle different content types
*/
public class ContentNegotiation {
/**
* Request JSON, receive JSON
*/
public static JsonObject fetchJSON(String url) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create(url))
.header("Accept", "application/json")
.GET()
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
// Parse JSON (using simple parsing or library)
String json = response.body();
return JsonParser.parseObject(json);
}
/**
* Request XML, receive XML
*/
public static String fetchXML(String url) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create(url))
.header("Accept", "application/xml")
.GET()
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
return response.body();
}
/**
* Check response content type
*/
public static String getContentType(HttpResponse<String> response) {
return response.headers()
.firstValue("content-type")
.orElse("text/plain");
}
/**
* Determine if response is JSON
*/
public static boolean isJSON(HttpResponse<String> response) {
return getContentType(response).contains("application/json");
}
/**
* Determine if response is XML
*/
public static boolean isXML(HttpResponse<String> response) {
return getContentType(response).contains("application/xml");
}
/**
* Handle different response types
*/
public static String handleDynamicContent(String url) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create(url))
.header("Accept", "application/json, application/xml")
.GET()
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
String contentType = getContentType(response);
if (contentType.contains("json")) {
return parseJSON(response.body());
} else if (contentType.contains("xml")) {
return parseXML(response.body());
} else {
return response.body();
}
}
private static String parseJSON(String json) {
// Parse and return structured data
return "Parsed JSON";
}
private static String parseXML(String xml) {
// Parse and return structured data
return "Parsed XML";
}
// Placeholder for JSON operations
static class JsonParser {
static JsonObject parseObject(String json) {
return new JsonObject();
}
}
static class JsonObject {
}
}
Chunked Transfer Encoding
Handling Chunked Responses:
/**
* Process chunked transfer encoded responses
*/
public class ChunkedTransfer {
/**
* The client automatically handles chunked encoding
*/
public static String handleChunkedResponse(String url) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create(url))
.GET()
.build();
// Chunked responses are transparently decompressed
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
return response.body();
}
/**
* Stream chunked response efficiently
*/
public static void streamChunked(String url) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create(url))
.GET()
.build();
HttpResponse<InputStream> response = client.send(request,
HttpResponse.BodyHandlers.ofInputStream());
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(response.body()))) {
String line;
while ((line = reader.readLine()) != null) {
// Process chunk
System.out.println("Chunk: " + line);
}
}
}
/**
* Check if response is chunked
*/
public static boolean isChunked(HttpResponse<String> response) {
String transferEncoding = response.headers()
.firstValue("transfer-encoding")
.orElse("");
return transferEncoding.equalsIgnoreCase("chunked");
}
}
Best Practices
1. Use Appropriate BodyHandler:
// ✓ Good - stream large files
HttpResponse<Path> response = client.send(request,
HttpResponse.BodyHandlers.ofFile(path));
// ✗ Bad - loading large file into memory
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
2. Set Content-Type Header:
HttpRequest request = HttpRequest.newBuilder(uri)
.POST(HttpRequest.BodyPublishers.ofString(json))
.header("Content-Type", "application/json")
.build();
3. Handle Large Responses with Streams:
HttpResponse<InputStream> response = client.send(request,
HttpResponse.BodyHandlers.ofInputStream());
try (var reader = new BufferedReader(
new InputStreamReader(response.body()))) {
String line;
while ((line = reader.readLine()) != null) {
// Process line
}
}
4. Validate Response Status:
HttpResponse<String> response = ...;
if (response.statusCode() >= 400) {
throw new IOException("HTTP " + response.statusCode());
}
5. Use Content Negotiation:
HttpRequest request = HttpRequest.newBuilder(uri)
.header("Accept", "application/json")
.GET()
.build();
These request and response patterns enable efficient and flexible HTTP communication in Java applications.