https://github.com/asynchttpclient/async-http-client
Asynchronous Http and WebSocket Client library for Java
https://github.com/asynchttpclient/async-http-client
ahc async asynchttpclient http-client java netty
Last synced: 19 days ago
JSON representation
Asynchronous Http and WebSocket Client library for Java
- Host: GitHub
- URL: https://github.com/asynchttpclient/async-http-client
- Owner: AsyncHttpClient
- License: other
- Created: 2011-03-07T13:41:46.000Z (about 15 years ago)
- Default Branch: main
- Last Pushed: 2025-04-02T19:58:01.000Z (about 1 year ago)
- Last Synced: 2025-05-05T15:57:11.366Z (12 months ago)
- Topics: ahc, async, asynchttpclient, http-client, java, netty
- Language: Java
- Homepage:
- Size: 18.2 MB
- Stars: 6,339
- Watchers: 351
- Forks: 1,599
- Open Issues: 110
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGES.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# Async Http Client
[](https://github.com/AsyncHttpClient/async-http-client/actions/workflows/builds.yml)
[](https://central.sonatype.com/artifact/org.asynchttpclient/async-http-client)
[](https://www.apache.org/licenses/LICENSE-2.0)
AsyncHttpClient (AHC) is a high-performance, asynchronous HTTP client for Java
built on top of [Netty](https://github.com/netty/netty).
It supports HTTP/1.1, HTTP/2, and WebSocket protocols.
## Table of Contents
- [Features](#features)
- [Requirements](#requirements)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Configuration](#configuration)
- [HTTP Requests](#http-requests)
- [Handling Responses](#handling-responses)
- [HTTP/2](#http2)
- [WebSocket](#websocket)
- [Authentication](#authentication)
- [Proxy Support](#proxy-support)
- [Community](#community)
- [License](#license)
## Features
- **HTTP/2 with multiplexing** — enabled by default over TLS via ALPN,
with connection multiplexing and GOAWAY handling
- **HTTP/1.1 and HTTP/1.0** — connection pooling and keep-alive
- **WebSocket** — text, binary, and ping/pong frame support
- **Asynchronous API** — non-blocking I/O with `ListenableFuture`
and `CompletableFuture`
- **Compression** — automatic gzip, deflate, Brotli, and Zstd decompression
- **Authentication** — Basic, Digest, NTLM, SPNEGO/Kerberos, and SCRAM-SHA-256
- **Proxy** — HTTP, SOCKS4, and SOCKS5 with CONNECT tunneling
- **Native transports** — optional Epoll, KQueue, and io_uring
- **Request/response filters** — intercept and transform at each stage
- **Cookie management** — RFC 6265-compliant cookie store
- **Multipart uploads** — file, byte array, input stream, and string parts
- **Resumable downloads** — built-in `ResumableIOExceptionFilter`
## Requirements
Java 11+
## Installation
**Maven:**
```xml
org.asynchttpclient
async-http-client
3.0.8
```
**Gradle:**
```groovy
implementation 'org.asynchttpclient:async-http-client:3.0.8'
```
Optional: Native Transport
For lower-latency I/O on Linux, add a native transport dependency:
```xml
io.netty
netty-transport-native-epoll
linux-x86_64
io.netty
netty-transport-native-io_uring
linux-x86_64
```
Then enable in config:
```java
AsyncHttpClient client = asyncHttpClient(config().setUseNativeTransport(true));
```
Optional: Brotli / Zstd Compression
```xml
com.aayushatharva.brotli4j
brotli4j
1.20.0
com.github.luben
zstd-jni
1.5.7-7
```
## Quick Start
Import the DSL helpers:
```java
import static org.asynchttpclient.Dsl.*;
```
Create a client, execute a request, and read the response:
```java
try (AsyncHttpClient client = asyncHttpClient()) {
// Asynchronous
client.prepareGet("https://www.example.com/")
.execute()
.toCompletableFuture()
.thenApply(Response::getResponseBody)
.thenAccept(System.out::println)
.join();
// Synchronous (blocking)
Response response = client.prepareGet("https://www.example.com/")
.execute()
.get();
}
```
> **Note:** `AsyncHttpClient` instances are long-lived, shared resources.
> Always close them when done. Creating a new client per request will degrade
> performance due to repeated thread pool and connection pool creation.
## Configuration
Use `config()` to build an `AsyncHttpClientConfig`:
```java
AsyncHttpClient client = asyncHttpClient(config()
.setConnectTimeout(Duration.ofSeconds(5))
.setRequestTimeout(Duration.ofSeconds(30))
.setMaxConnections(500)
.setMaxConnectionsPerHost(100)
.setFollowRedirect(true)
.setMaxRedirects(5)
.setCompressionEnforced(true));
```
## HTTP Requests
### Sending Requests
**Bound** — build directly from the client:
```java
Response response = client
.prepareGet("https://api.example.com/users")
.addHeader("Accept", "application/json")
.addQueryParam("page", "1")
.execute()
.get();
```
**Unbound** — build standalone via DSL, then execute:
```java
Request request = get("https://api.example.com/users")
.addHeader("Accept", "application/json")
.addQueryParam("page", "1")
.build();
Response response = client.executeRequest(request).get();
```
Methods: `GET`, `POST`, `PUT`, `DELETE`, `PATCH`, `HEAD`, `OPTIONS`, `TRACE`.
### Request Bodies
Use `setBody` to attach a body. Supported types:
| Type | Description |
|---|---|
| `String` | Text content |
| `byte[]` | Raw bytes |
| `ByteBuffer` | NIO buffer |
| `InputStream` | Streaming input |
| `File` | File content |
| `Publisher` | Reactive stream |
| `BodyGenerator` | Custom body generation |
```java
Response response = client
.preparePost("https://api.example.com/data")
.setHeader("Content-Type", "application/json")
.setBody("{\"name\": \"value\"}")
.execute()
.get();
```
For streaming bodies, see `FeedableBodyGenerator` which lets you push chunks
asynchronously.
### Multipart Uploads
```java
Response response = client
.preparePost("https://api.example.com/upload")
.addBodyPart(new FilePart("file", new File("report.pdf"), "application/pdf"))
.addBodyPart(new StringPart("description", "Monthly report"))
.execute()
.get();
```
Part types: `FilePart`, `ByteArrayPart`, `InputStreamPart`, `StringPart`.
## Handling Responses
### Blocking
```java
Response response = client.prepareGet("https://www.example.com/").execute().get();
```
> Useful for debugging, but defeats the purpose of an async client in production.
### ListenableFuture
`execute()` returns a `ListenableFuture` that supports completion listeners:
```java
ListenableFuture future = client
.prepareGet("https://www.example.com/")
.execute();
future.addListener(() -> {
Response response = future.get();
System.out.println(response.getStatusCode());
}, executor);
```
> If `executor` is `null`, the callback runs on the Netty I/O thread.
> **Never block** inside I/O thread callbacks.
### CompletableFuture
```java
client.prepareGet("https://www.example.com/")
.execute()
.toCompletableFuture()
.thenApply(Response::getResponseBody)
.thenAccept(System.out::println)
.join();
```
### AsyncCompletionHandler
For most async use cases, extend `AsyncCompletionHandler` — it buffers the
full response and gives you a single `onCompleted(Response)` callback:
```java
client.prepareGet("https://www.example.com/")
.execute(new AsyncCompletionHandler() {
@Override
public String onCompleted(Response response) {
return response.getResponseBody();
}
});
```
### AsyncHandler
For fine-grained control, implement `AsyncHandler` directly. This lets you
inspect status, headers, and body chunks as they arrive and abort early:
```java
Future future = client
.prepareGet("https://www.example.com/")
.execute(new AsyncHandler<>() {
private int status;
@Override
public State onStatusReceived(HttpResponseStatus s) {
status = s.getStatusCode();
return State.CONTINUE;
}
@Override
public State onHeadersReceived(HttpHeaders headers) {
return State.CONTINUE;
}
@Override
public State onBodyPartReceived(HttpResponseBodyPart part) {
return State.ABORT; // stop early — we only needed the status
}
@Override
public Integer onCompleted() {
return status;
}
@Override
public void onThrowable(Throwable t) {
t.printStackTrace();
}
});
```
## HTTP/2
HTTP/2 is **enabled by default** for HTTPS connections via ALPN negotiation.
The client uses HTTP/2 when the server supports it and falls back to HTTP/1.1
otherwise. No additional configuration is required.
- **Connection multiplexing** — concurrent streams over a single TCP connection
- **GOAWAY handling** — graceful connection draining on server shutdown
- **PING keepalive** — configurable ping frames to keep connections alive
### HTTP/2 Configuration
```java
AsyncHttpClient client = asyncHttpClient(config()
.setHttp2MaxConcurrentStreams(100)
.setHttp2InitialWindowSize(65_535)
.setHttp2MaxFrameSize(16_384)
.setHttp2MaxHeaderListSize(8_192)
.setHttp2PingInterval(Duration.ofSeconds(30)) // keepalive pings
.setHttp2CleartextEnabled(true)); // h2c prior knowledge
```
To force HTTP/1.1, disable HTTP/2:
```java
AsyncHttpClient client = asyncHttpClient(config().setHttp2Enabled(false));
```
## WebSocket
```java
WebSocket ws = client
.prepareGet("wss://echo.example.com/")
.execute(new WebSocketUpgradeHandler.Builder()
.addWebSocketListener(new WebSocketListener() {
@Override
public void onOpen(WebSocket ws) {
ws.sendTextFrame("Hello!");
}
@Override
public void onTextFrame(String payload, boolean finalFragment, int rsv) {
System.out.println(payload);
}
@Override
public void onClose(WebSocket ws, int code, String reason) {}
@Override
public void onError(Throwable t) { t.printStackTrace(); }
})
.build())
.get();
```
## Authentication
```java
// Client-wide Basic auth
AsyncHttpClient client = asyncHttpClient(config()
.setRealm(basicAuthRealm("user", "password")));
// Per-request Digest auth
Response response = client
.prepareGet("https://api.example.com/protected")
.setRealm(digestAuthRealm("user", "password").build())
.execute()
.get();
// SCRAM-SHA-256 (RFC 7804)
Response response = client
.prepareGet("https://api.example.com/protected")
.setRealm(scramSha256AuthRealm("user", "password").build())
.execute()
.get();
```
Supported schemes: **Basic**, **Digest**, **NTLM**, **SPNEGO/Kerberos**, **SCRAM-SHA-256**.
## Proxy Support
```java
// HTTP proxy
AsyncHttpClient client = asyncHttpClient(config()
.setProxyServer(proxyServer("proxy.example.com", 8080)));
// Authenticated proxy
AsyncHttpClient client = asyncHttpClient(config()
.setProxyServer(proxyServer("proxy.example.com", 8080)
.setRealm(basicAuthRealm("proxyUser", "proxyPassword"))));
```
SOCKS4 and SOCKS5 proxies are also supported.
## Community
- [GitHub Discussions](https://github.com/AsyncHttpClient/async-http-client/discussions) — questions, ideas, and general discussion
- [Issue Tracker](https://github.com/AsyncHttpClient/async-http-client/issues) — bug reports and feature requests
## License
[Apache License 2.0](LICENSE.txt)