{"id":15014277,"url":"https://github.com/asynchttpclient/async-http-client","last_synced_at":"2026-04-02T16:07:51.061Z","repository":{"id":37335545,"uuid":"1450115","full_name":"AsyncHttpClient/async-http-client","owner":"AsyncHttpClient","description":"Asynchronous Http and WebSocket Client library for Java ","archived":false,"fork":false,"pushed_at":"2025-04-02T19:58:01.000Z","size":19089,"stargazers_count":6339,"open_issues_count":110,"forks_count":1599,"subscribers_count":351,"default_branch":"main","last_synced_at":"2025-05-05T15:57:11.366Z","etag":null,"topics":["ahc","async","asynchttpclient","http-client","java","netty"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AsyncHttpClient.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2011-03-07T13:41:46.000Z","updated_at":"2025-04-30T02:17:51.000Z","dependencies_parsed_at":"2023-12-22T19:23:03.060Z","dependency_job_id":"92340bda-cf5a-4473-9ee4-62a9d0120839","html_url":"https://github.com/AsyncHttpClient/async-http-client","commit_stats":{"total_commits":3950,"total_committers":233,"mean_commits":"16.952789699570815","dds":0.6678481012658228,"last_synced_commit":"c4812b22a4a1c2e3e0e8bdba0f5103f60a54cc86"},"previous_names":[],"tags_count":288,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AsyncHttpClient%2Fasync-http-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AsyncHttpClient%2Fasync-http-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AsyncHttpClient%2Fasync-http-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AsyncHttpClient%2Fasync-http-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AsyncHttpClient","download_url":"https://codeload.github.com/AsyncHttpClient/async-http-client/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253798241,"owners_count":21966039,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ahc","async","asynchttpclient","http-client","java","netty"],"created_at":"2024-09-24T19:45:24.550Z","updated_at":"2026-04-02T16:07:51.049Z","avatar_url":"https://github.com/AsyncHttpClient.png","language":"Java","readme":"# Async Http Client\n\n[![Build](https://github.com/AsyncHttpClient/async-http-client/actions/workflows/builds.yml/badge.svg)](https://github.com/AsyncHttpClient/async-http-client/actions/workflows/builds.yml)\n[![Maven Central](https://img.shields.io/maven-central/v/org.asynchttpclient/async-http-client)](https://central.sonatype.com/artifact/org.asynchttpclient/async-http-client)\n[![License](https://img.shields.io/github/license/AsyncHttpClient/async-http-client)](https://www.apache.org/licenses/LICENSE-2.0)\n\nAsyncHttpClient (AHC) is a high-performance, asynchronous HTTP client for Java\nbuilt on top of [Netty](https://github.com/netty/netty).\nIt supports HTTP/1.1, HTTP/2, and WebSocket protocols.\n\n## Table of Contents\n\n- [Features](#features)\n- [Requirements](#requirements)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [HTTP Requests](#http-requests)\n- [Handling Responses](#handling-responses)\n- [HTTP/2](#http2)\n- [WebSocket](#websocket)\n- [Authentication](#authentication)\n- [Proxy Support](#proxy-support)\n- [Community](#community)\n- [License](#license)\n\n## Features\n\n- **HTTP/2 with multiplexing** — enabled by default over TLS via ALPN,\n  with connection multiplexing and GOAWAY handling\n- **HTTP/1.1 and HTTP/1.0** — connection pooling and keep-alive\n- **WebSocket** — text, binary, and ping/pong frame support\n- **Asynchronous API** — non-blocking I/O with `ListenableFuture`\n  and `CompletableFuture`\n- **Compression** — automatic gzip, deflate, Brotli, and Zstd decompression\n- **Authentication** — Basic, Digest, NTLM, SPNEGO/Kerberos, and SCRAM-SHA-256\n- **Proxy** — HTTP, SOCKS4, and SOCKS5 with CONNECT tunneling\n- **Native transports** — optional Epoll, KQueue, and io_uring\n- **Request/response filters** — intercept and transform at each stage\n- **Cookie management** — RFC 6265-compliant cookie store\n- **Multipart uploads** — file, byte array, input stream, and string parts\n- **Resumable downloads** — built-in `ResumableIOExceptionFilter`\n\n## Requirements\n\nJava 11+\n\n## Installation\n\n**Maven:**\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.asynchttpclient\u003c/groupId\u003e\n    \u003cartifactId\u003easync-http-client\u003c/artifactId\u003e\n    \u003cversion\u003e3.0.8\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n**Gradle:**\n\n```groovy\nimplementation 'org.asynchttpclient:async-http-client:3.0.8'\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eOptional: Native Transport\u003c/b\u003e\u003c/summary\u003e\n\nFor lower-latency I/O on Linux, add a native transport dependency:\n\n```xml\n\u003c!-- Epoll (Linux) --\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.netty\u003c/groupId\u003e\n    \u003cartifactId\u003enetty-transport-native-epoll\u003c/artifactId\u003e\n    \u003cclassifier\u003elinux-x86_64\u003c/classifier\u003e\n\u003c/dependency\u003e\n\n\u003c!-- io_uring (Linux) --\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.netty\u003c/groupId\u003e\n    \u003cartifactId\u003enetty-transport-native-io_uring\u003c/artifactId\u003e\n    \u003cclassifier\u003elinux-x86_64\u003c/classifier\u003e\n\u003c/dependency\u003e\n```\n\nThen enable in config:\n\n```java\nAsyncHttpClient client = asyncHttpClient(config().setUseNativeTransport(true));\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eOptional: Brotli / Zstd Compression\u003c/b\u003e\u003c/summary\u003e\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.aayushatharva.brotli4j\u003c/groupId\u003e\n    \u003cartifactId\u003ebrotli4j\u003c/artifactId\u003e\n    \u003cversion\u003e1.20.0\u003c/version\u003e\n\u003c/dependency\u003e\n\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.github.luben\u003c/groupId\u003e\n    \u003cartifactId\u003ezstd-jni\u003c/artifactId\u003e\n    \u003cversion\u003e1.5.7-7\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n\u003c/details\u003e\n\n## Quick Start\n\nImport the DSL helpers:\n\n```java\nimport static org.asynchttpclient.Dsl.*;\n```\n\nCreate a client, execute a request, and read the response:\n\n```java\ntry (AsyncHttpClient client = asyncHttpClient()) {\n    // Asynchronous\n    client.prepareGet(\"https://www.example.com/\")\n        .execute()\n        .toCompletableFuture()\n        .thenApply(Response::getResponseBody)\n        .thenAccept(System.out::println)\n        .join();\n\n    // Synchronous (blocking)\n    Response response = client.prepareGet(\"https://www.example.com/\")\n        .execute()\n        .get();\n}\n```\n\n\u003e **Note:** `AsyncHttpClient` instances are long-lived, shared resources.\n\u003e Always close them when done. Creating a new client per request will degrade\n\u003e performance due to repeated thread pool and connection pool creation.\n\n## Configuration\n\nUse `config()` to build an `AsyncHttpClientConfig`:\n\n```java\nAsyncHttpClient client = asyncHttpClient(config()\n    .setConnectTimeout(Duration.ofSeconds(5))\n    .setRequestTimeout(Duration.ofSeconds(30))\n    .setMaxConnections(500)\n    .setMaxConnectionsPerHost(100)\n    .setFollowRedirect(true)\n    .setMaxRedirects(5)\n    .setCompressionEnforced(true));\n```\n\n## HTTP Requests\n\n### Sending Requests\n\n**Bound** — build directly from the client:\n\n```java\nResponse response = client\n    .prepareGet(\"https://api.example.com/users\")\n    .addHeader(\"Accept\", \"application/json\")\n    .addQueryParam(\"page\", \"1\")\n    .execute()\n    .get();\n```\n\n**Unbound** — build standalone via DSL, then execute:\n\n```java\nRequest request = get(\"https://api.example.com/users\")\n    .addHeader(\"Accept\", \"application/json\")\n    .addQueryParam(\"page\", \"1\")\n    .build();\n\nResponse response = client.executeRequest(request).get();\n```\n\nMethods: `GET`, `POST`, `PUT`, `DELETE`, `PATCH`, `HEAD`, `OPTIONS`, `TRACE`.\n\n### Request Bodies\n\nUse `setBody` to attach a body. Supported types:\n\n| Type | Description |\n|---|---|\n| `String` | Text content |\n| `byte[]` | Raw bytes |\n| `ByteBuffer` | NIO buffer |\n| `InputStream` | Streaming input |\n| `File` | File content |\n| `Publisher\u003cByteBuf\u003e` | Reactive stream |\n| `BodyGenerator` | Custom body generation |\n\n```java\nResponse response = client\n    .preparePost(\"https://api.example.com/data\")\n    .setHeader(\"Content-Type\", \"application/json\")\n    .setBody(\"{\\\"name\\\": \\\"value\\\"}\")\n    .execute()\n    .get();\n```\n\nFor streaming bodies, see `FeedableBodyGenerator` which lets you push chunks\nasynchronously.\n\n### Multipart Uploads\n\n```java\nResponse response = client\n    .preparePost(\"https://api.example.com/upload\")\n    .addBodyPart(new FilePart(\"file\", new File(\"report.pdf\"), \"application/pdf\"))\n    .addBodyPart(new StringPart(\"description\", \"Monthly report\"))\n    .execute()\n    .get();\n```\n\nPart types: `FilePart`, `ByteArrayPart`, `InputStreamPart`, `StringPart`.\n\n## Handling Responses\n\n### Blocking\n\n```java\nResponse response = client.prepareGet(\"https://www.example.com/\").execute().get();\n```\n\n\u003e Useful for debugging, but defeats the purpose of an async client in production.\n\n### ListenableFuture\n\n`execute()` returns a `ListenableFuture` that supports completion listeners:\n\n```java\nListenableFuture\u003cResponse\u003e future = client\n    .prepareGet(\"https://www.example.com/\")\n    .execute();\n\nfuture.addListener(() -\u003e {\n    Response response = future.get();\n    System.out.println(response.getStatusCode());\n}, executor);\n```\n\n\u003e If `executor` is `null`, the callback runs on the Netty I/O thread.\n\u003e **Never block** inside I/O thread callbacks.\n\n### CompletableFuture\n\n```java\nclient.prepareGet(\"https://www.example.com/\")\n    .execute()\n    .toCompletableFuture()\n    .thenApply(Response::getResponseBody)\n    .thenAccept(System.out::println)\n    .join();\n```\n\n### AsyncCompletionHandler\n\nFor most async use cases, extend `AsyncCompletionHandler` — it buffers the\nfull response and gives you a single `onCompleted(Response)` callback:\n\n```java\nclient.prepareGet(\"https://www.example.com/\")\n    .execute(new AsyncCompletionHandler\u003cString\u003e() {\n        @Override\n        public String onCompleted(Response response) {\n            return response.getResponseBody();\n        }\n    });\n```\n\n### AsyncHandler\n\nFor fine-grained control, implement `AsyncHandler` directly. This lets you\ninspect status, headers, and body chunks as they arrive and abort early:\n\n```java\nFuture\u003cInteger\u003e future = client\n    .prepareGet(\"https://www.example.com/\")\n    .execute(new AsyncHandler\u003c\u003e() {\n        private int status;\n\n        @Override\n        public State onStatusReceived(HttpResponseStatus s) {\n            status = s.getStatusCode();\n            return State.CONTINUE;\n        }\n\n        @Override\n        public State onHeadersReceived(HttpHeaders headers) {\n            return State.CONTINUE;\n        }\n\n        @Override\n        public State onBodyPartReceived(HttpResponseBodyPart part) {\n            return State.ABORT; // stop early — we only needed the status\n        }\n\n        @Override\n        public Integer onCompleted() {\n            return status;\n        }\n\n        @Override\n        public void onThrowable(Throwable t) {\n            t.printStackTrace();\n        }\n    });\n```\n\n## HTTP/2\n\nHTTP/2 is **enabled by default** for HTTPS connections via ALPN negotiation.\nThe client uses HTTP/2 when the server supports it and falls back to HTTP/1.1\notherwise. No additional configuration is required.\n\n- **Connection multiplexing** — concurrent streams over a single TCP connection\n- **GOAWAY handling** — graceful connection draining on server shutdown\n- **PING keepalive** — configurable ping frames to keep connections alive\n\n### HTTP/2 Configuration\n\n```java\nAsyncHttpClient client = asyncHttpClient(config()\n    .setHttp2MaxConcurrentStreams(100)\n    .setHttp2InitialWindowSize(65_535)\n    .setHttp2MaxFrameSize(16_384)\n    .setHttp2MaxHeaderListSize(8_192)\n    .setHttp2PingInterval(Duration.ofSeconds(30))  // keepalive pings\n    .setHttp2CleartextEnabled(true));               // h2c prior knowledge\n```\n\nTo force HTTP/1.1, disable HTTP/2:\n\n```java\nAsyncHttpClient client = asyncHttpClient(config().setHttp2Enabled(false));\n```\n\n## WebSocket\n\n```java\nWebSocket ws = client\n    .prepareGet(\"wss://echo.example.com/\")\n    .execute(new WebSocketUpgradeHandler.Builder()\n        .addWebSocketListener(new WebSocketListener() {\n            @Override\n            public void onOpen(WebSocket ws) {\n                ws.sendTextFrame(\"Hello!\");\n            }\n\n            @Override\n            public void onTextFrame(String payload, boolean finalFragment, int rsv) {\n                System.out.println(payload);\n            }\n\n            @Override\n            public void onClose(WebSocket ws, int code, String reason) {}\n\n            @Override\n            public void onError(Throwable t) { t.printStackTrace(); }\n        })\n        .build())\n    .get();\n```\n\n## Authentication\n\n```java\n// Client-wide Basic auth\nAsyncHttpClient client = asyncHttpClient(config()\n    .setRealm(basicAuthRealm(\"user\", \"password\")));\n\n// Per-request Digest auth\nResponse response = client\n    .prepareGet(\"https://api.example.com/protected\")\n    .setRealm(digestAuthRealm(\"user\", \"password\").build())\n    .execute()\n    .get();\n\n// SCRAM-SHA-256 (RFC 7804)\nResponse response = client\n    .prepareGet(\"https://api.example.com/protected\")\n    .setRealm(scramSha256AuthRealm(\"user\", \"password\").build())\n    .execute()\n    .get();\n```\n\nSupported schemes: **Basic**, **Digest**, **NTLM**, **SPNEGO/Kerberos**, **SCRAM-SHA-256**.\n\n## Proxy Support\n\n```java\n// HTTP proxy\nAsyncHttpClient client = asyncHttpClient(config()\n    .setProxyServer(proxyServer(\"proxy.example.com\", 8080)));\n\n// Authenticated proxy\nAsyncHttpClient client = asyncHttpClient(config()\n    .setProxyServer(proxyServer(\"proxy.example.com\", 8080)\n        .setRealm(basicAuthRealm(\"proxyUser\", \"proxyPassword\"))));\n```\n\nSOCKS4 and SOCKS5 proxies are also supported.\n\n## Community\n\n- [GitHub Discussions](https://github.com/AsyncHttpClient/async-http-client/discussions) — questions, ideas, and general discussion\n- [Issue Tracker](https://github.com/AsyncHttpClient/async-http-client/issues) — bug reports and feature requests\n\n## License\n\n[Apache License 2.0](LICENSE.txt)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasynchttpclient%2Fasync-http-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fasynchttpclient%2Fasync-http-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasynchttpclient%2Fasync-http-client/lists"}