# Io / Github / Biezhi / Java11 / Http

## Overview

This module contains example code demonstrating how to use Java 11's built-in HTTP Client API (`java.net.http` package). It lives inside the `io.github.biezhi.java11` collection of examples, which collectively showcase new language and standard library features introduced in JDK 11. The module covers synchronous and asynchronous HTTP requests, file uploads and downloads, proxy configuration, basic authentication, HTTP/2 support, and parallel request execution.

It is **not** a library or framework — it is an educational example class that you can study or copy snippets from when you need to make HTTP calls using the modern JDK 11 client rather than the legacy `java.net.URL` / `HttpURLConnection` approach.

---

## Key Classes

### `Example`

[source](src/main/java/io/github/biezhi/java11/http/Example.java:26)

The primary class in this package. It provides a suite of static and instance methods, each demonstrating a different HTTP client pattern available in Java 11.

The class uses the following JDK 11 APIs:

- `java.net.http.HttpClient` — the new client, created via `HttpClient.newHttpClient()` or `HttpClient.newBuilder()...build()` for custom configuration.
- `java.net.http.HttpRequest` — built with `HttpRequest.newBuilder()`, supporting URI, headers, and request body configuration.
- `java.net.http.HttpResponse` — returned from client calls, carrying status code, headers, and body.
- `java.net.http.HttpResponse.BodyHandlers` — predefined handlers for converting the response body to `String`, `Path` (file), or discarding it entirely.
- `java.util.concurrent.CompletableFuture` — used for all asynchronous operations.

#### Methods

##### `syncGet(String uri)`

[source](src/main/java/io/github/biezhi/java11/http/Example.java:29)

Performs a synchronous GET request. Creates a default `HttpClient`, builds an `HttpRequest` with the given URI, and calls `client.send(...)`. The response body is captured as a `String` via `BodyHandlers.ofString()`. Prints the status code and body to stdout.

This is the simplest way to make an HTTP call with Java 11 — blocking and straightforward.

##### `asyncGet(String uri)`

[source](src/main/java/io/github/biezhi/java11/http/Example.java:43)

Performs an asynchronous GET request. Uses `client.sendAsync(...)` to return a `CompletableFuture<HttpResponse<String>>`. Attaches a `whenComplete` handler to print the response body and status code (or the exception stack trace on error), then calls `.join()` to block until the result arrives.

This pattern is useful when you need non-blocking behavior but still want to wait for the result at the call site.

##### `asyncPost()`

[source](src/main/java/io/github/biezhi/java11/http/Example.java:61)

Performs an asynchronous POST request, sending a JSON body constructed from a `Foo` POJO serialized with Gson. The request targets `https://httpbin.org/post`, a public HTTP testing service that echoes back the request details. Sets the `Content-Type` header to `application/json` and uses `BodyPublishers.ofString(jsonBody)` as the request body.

This demonstrates the full POST flow: object -> JSON -> request body -> async send -> response.

##### `downloadFile()`

[source](src/main/java/io/github/biezhi/java11/http/Example.java:88)

Downloads the content of a URL (`https://labs.consol.de/`) directly to a temporary file on disk. Creates a temp file via `Files.createTempFile(...)`, then calls `client.send(...)` with `BodyHandlers.ofFile(tempFile)`. The JDK 11 runtime writes the HTTP response body to the file automatically.

This replaces the old pattern of opening an `InputStream` and manually copying bytes to a file.

##### `uploadFile()`

[source](src/main/java/io/github/biezhi/java11/http/Example.java:103)

Uploads the contents of a local file (`/tmp/files-to-upload.txt`) to `http://localhost:8080/upload/` using a POST request. The file is published as the request body via `BodyPublishers.ofFile(...)`. The response body is discarded since only the status code matters.

This shows how to stream a local file into an HTTP request body without loading the entire file into memory.

##### `proxy()`

[source](src/main/java/io/github/biezhi/java11/http/Example.java:117)

Configures an `HttpClient` to route traffic through a proxy at `127.0.0.1:1080`. Uses `HttpClient.newBuilder().proxy(ProxySelector.of(...)).build()` to set the proxy selector on the client, then makes a regular GET request.

This demonstrates proxy configuration at the client level.

##### `basicAuth()`

[source](src/main/java/io/github/biezhi/java11/http/Example.java:133)

Configures an `HttpClient` with a custom `Authenticator` that supplies hardcoded credentials (`username` / `password`). When the server challenges the request, the client automatically retries with a `Basic` authorization header.

This is the JDK 11 way of handling HTTP basic authentication. In older JDK versions you would have had to manually encode the `Authorization` header yourself.

##### `http2()`

[source](src/main/java/io/github/biezhi/java11/http/Example.java:154)

Creates an `HttpClient` that uses the HTTP/2 protocol and follows normal redirect behavior. Makes an async GET to `https://http2.akamai.com/demo`, a test endpoint specifically designed to verify HTTP/2 support. The response body (containing test results) is printed to stdout.

Note that HTTP/2 support requires a JDK built with an SSL provider that supports HTTP/2 (e.g., Oracle JDK or OpenJDK with the built-in TLS implementation).

##### `getURIs(List<URI> uris)`

[source](src/main/java/io/github/biezhi/java11/http/Example.java:175)

Executes **parallel** HTTP requests against a list of URIs. Converts each URI into a `HttpRequest`, then maps each request to a `CompletableFuture` via `sendAsync(...)`. Uses `CompletableFuture.allOf(...).join()` to wait for **all** requests to complete before returning.

This is the idiomatic Java 11 pattern for fan-out parallel HTTP calls. Each request runs concurrently on the client's internal async executor.

##### `main(String[] args)`

[source](src/main/java/io/github/biezhi/java11/http/Example.java:188)

Entry point for running the examples from the command line. Currently uncommented calls `asyncPost()`; all other methods are commented out. This is clearly a playground class — uncomment individual lines to test different patterns.

---

### `Foo`

[source](src/main/java/io/github/biezhi/java11/http/Foo.java:7)

A minimal POJO with two public fields:

| Field | Type | Description |
|-------|------|-------------|
| `name` | `String` | A name (used in the POST example with the value "王爵nice") |
| `url` | `String` | A URL (used in the POST example with the value "https://github.com/biezhi") |

This class has no methods, no constructors, and no annotations. It is intended solely as a JSON payload for the `asyncPost()` example. The `Gson` library serializes it to a JSON string and sends it as the request body.

---

## How It Works

### Typical Request Lifecycle

Here is the flow for a typical synchronous request (illustrated via `syncGet`):

```mermaid
flowchart TD
    A["Example.syncGet(uri)"] --> B["HttpClient.newHttpClient()"]
    B --> C["HttpRequest.newBuilder().uri(...).build()"]
    C --> D["client.send(request, ofString())"]
    D --> E["HttpResponse<String>"]
    E --> F["Print status + body"]
```

1. A default `HttpClient` is created with `HttpClient.newHttpClient()`. This client uses an internal thread pool for async operations and follows `GET` redirects automatically.
2. An `HttpRequest` is built via the builder pattern, setting the target URI.
3. `client.send()` is called with the request and a `BodyHandlers.ofString()` body handler. The method blocks until the response is fully received.
4. The `HttpResponse` object is returned, providing access to the status code (`response.statusCode()`), headers, and body (`response.body()`).

### Asynchronous Request Flow

For async operations (`asyncGet`, `asyncPost`, `http2`):

```mermaid
sequenceDiagram
    participant Caller
    participant Client as HttpClient
    participant Future as CompletableFuture
    participant Handler as whenComplete callback
    Caller->>Client: sendAsync(request, handler)
    Client-->>Future: returns immediately
    Note over Future: background thread performs HTTP call
    alt Success
        Client->>Handler: invoke with response, null
        Handler->>Handler: print body and status
    else Error
        Client->>Handler: invoke with null, exception
        Handler->>Handler: print stack trace
    end
    Handler->>Caller: join() returns
```

1. `sendAsync()` returns a `CompletableFuture` **immediately**, without blocking.
2. The HTTP call proceeds on a background thread.
3. `whenComplete()` registers a callback that fires when the response arrives (or when an error occurs).
4. `.join()` blocks the calling thread until the future completes, ensuring the example program does not exit before the response is printed.

### Parallel Requests

The `getURIs()` method demonstrates a fan-out pattern:

```mermaid
flowchart LR
    A["List<URI> uris"] --> B["Stream.map(newBuilder)"]
    B --> C["List<HttpRequest>"]
    C --> D["Stream.map(sendAsync)"]
    D --> E["List<CompletableFuture>"]
    E --> F["CompletableFuture.allOf()"]
    F --> G[".join() — all complete"]
```

Each URI is converted to a request, each request is fired asynchronously, and `CompletableFuture.allOf()` creates a combined future that completes when **all** individual requests are done.

---

## Data Model

### `Foo` — JSON Payload

[source](src/main/java/io/github/biezhi/java11/http/Foo.java:7)

```java
public class Foo {
    String name;   // e.g., "王爵nice"
    String url;    // e.g., "https://github.com/biezhi"
}
```

This is the only data-bearing class in the module. It is a plain Java object with two `String` fields and no behavior. Its sole purpose is to serve as a Gson serialization target for the POST example, producing JSON like:

```json
{"name": "王爵nice", "url": "https://github.com/biezhi"}
```

---

## Dependencies and Integration

### External Dependencies

| Dependency | Use |
|------------|-----|
| `com.google.gson.Gson` | Serializes `Foo` objects to JSON strings for POST request bodies |

### JDK 11 Built-in APIs Used

| API | Class | Purpose |
|-----|-------|---------|
| `java.net.http.HttpClient` | `HttpClient` | HTTP client for sending requests |
| `java.net.http.HttpRequest` | `HttpRequest` | Builder for HTTP requests (method, URI, headers, body) |
| `java.net.http.HttpResponse` | `HttpResponse<T>` | Response envelope with status, headers, and typed body |
| `java.net.http.HttpRequest.BodyPublishers` | Static utility | Creates body publishers from `String`, `Path`, `InputStream`, `byte[]`, etc. |
| `java.net.http.HttpResponse.BodyHandlers` | Static utility | Converts response streams into `String`, `Path`, `byte[]`, etc. |
| `java.util.concurrent.CompletableFuture` | `CompletableFuture<T>` | Async result wrapper for non-blocking requests |

### Internal Relationships

```mermaid
flowchart TD
    E["Example<br/>10 example methods"]
    F["Foo<br/>POJO payload"]
    E -->|"Gson.toJson()"| F
```

The `Example` class is the sole consumer of the `Foo` class. The `Foo` instance is serialized with Gson and sent as the body of an async POST request.

---

## Notes for Developers

- **Playground class**: The `main()` method has all calls commented out except `asyncPost()`. This is clearly intended for interactive experimentation — uncomment individual method calls to test different patterns.

- **Default client behavior**: `HttpClient.newHttpClient()` creates a client that:
  - Follows `GET` and `HEAD` redirects automatically.
  - Uses HTTP/1.1 by default (set `.version(HttpClient.Version.HTTP_2)` for HTTP/2).
  - Has no timeout set — consider using `.connectTimeout(Duration.ofSeconds(10))` for production use.

- **Gson dependency**: The `asyncPost()` method requires `com.google.gson.Gson` on the classpath. If you remove the Gson dependency, the POST example will not compile.

- **Hardcoded credentials**: The `basicAuth()` method embeds credentials (`"username"`, `"password"`) directly in the code. In a real application, these should come from environment variables, a secrets manager, or a configuration file.

- **Hardcoded URLs**: All target URLs (`httpbin.org`, `labs.consol.de`, `localhost:8080`) are hardcoded. For production use, externalize these to configuration.

- **Resource cleanup**: `HttpClient` does not need explicit cleanup in modern Java. However, if you create many clients over the lifetime of a long-running application, consider reusing a single `HttpClient` instance (it is thread-safe) rather than calling `newHttpClient()` repeatedly.

- **Thread safety**: `HttpClient`, `HttpRequest`, and `HttpResponse` instances are thread-safe. `CompletableFuture` returned by `sendAsync` is also thread-safe. You can safely share clients across threads.
