Skip to content

Commit c951ac3

Browse files
committed
Improve README
1 parent bd5538e commit c951ac3

File tree

1 file changed

+194
-131
lines changed

1 file changed

+194
-131
lines changed

README.md

+194-131
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,15 @@
1-
Async Http Client ([@AsyncHttpClient](https://twitter.com/AsyncHttpClient) on twitter) [![Build Status](https://travis-ci.org/AsyncHttpClient/async-http-client.svg?branch=master)](https://travis-ci.org/AsyncHttpClient/async-http-client)
2-
---------------------------------------------------
1+
# Async Http Client [![Build Status](https://travis-ci.org/AsyncHttpClient/async-http-client.svg?branch=master)](https://travis-ci.org/AsyncHttpClient/async-http-client) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.asynchttpclient/async-http-client/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.asynchttpclient/async-http-client/)
32

4-
[Javadoc](http://www.javadoc.io/doc/org.asynchttpclient/async-http-client/)
3+
Follow [@AsyncHttpClient](https://twitter.com/AsyncHttpClient) on Twitter.
54

6-
[Getting](https://jfarcand.wordpress.com/2010/12/21/going-asynchronous-using-asynchttpclient-the-basic/) [started](https://jfarcand.wordpress.com/2011/01/04/going-asynchronous-using-asynchttpclient-the-complex/), and use [WebSockets](http://jfarcand.wordpress.com/2011/12/21/writing-websocket-clients-using-asynchttpclient/)
5+
The AsyncHttpClient (AHC) library allows Java applications to easily execute HTTP requests and asynchronously process HTTP responses.
6+
The library also supports the WebSocket Protocol.
77

8-
The Async Http Client library's purpose is to allow Java applications to easily execute HTTP requests and asynchronously process the HTTP responses.
9-
The library also supports the WebSocket Protocol. The Async HTTP Client library is simple to use.
10-
11-
It's built on top of [Netty](https://github.com/netty/netty) and currently requires JDK8.
12-
13-
Latest `version`: [![Maven](https://img.shields.io/maven-central/v/org.asynchttpclient/async-http-client.svg)](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.asynchttpclient%22%20AND%20a%3A%22async-http-client%22)
8+
It's built on top of [Netty](https://github.com/netty/netty). I's currently compiled on Java 8 but runs on Java 9 too.
149

1510
## Installation
1611

17-
First, in order to add it to your Maven project, simply download from Maven central or add this dependency:
12+
Binaries are deployed on Maven central:
1813

1914
```xml
2015
<dependency>
@@ -24,168 +19,197 @@ First, in order to add it to your Maven project, simply download from Maven cent
2419
</dependency>
2520
```
2621

27-
## Usage
22+
## Basics
2823

29-
Then in your code you can simply do
24+
Feel free to check the [Javadoc](http://www.javadoc.io/doc/org.asynchttpclient/async-http-client/) or the code for more information.
3025

31-
```java
32-
import org.asynchttpclient.*;
33-
import java.util.concurrent.Future;
26+
### Dsl
3427

35-
AsyncHttpClient asyncHttpClient = new DefaultAsyncHttpClient();
36-
Future<Response> f = asyncHttpClient.prepareGet("http://www.example.com/").execute();
37-
Response r = f.get();
38-
```
28+
Import the Dsl helpers to use convenient methods to bootstrap components:
3929

40-
Note that in this case all the content must be read fully in memory, even if you used `getResponseBodyAsStream()` method on returned `Response` object.
30+
```java
31+
import static org.asynchttpclient.Dsl.*;
32+
```
4133

42-
You can also accomplish asynchronous (non-blocking) operation without using a Future if you want to receive and process the response in your handler:
34+
### Client
4335

4436
```java
45-
import org.asynchttpclient.*;
46-
import java.util.concurrent.Future;
47-
48-
AsyncHttpClient asyncHttpClient = new DefaultAsyncHttpClient();
49-
asyncHttpClient.prepareGet("http://www.example.com/").execute(new AsyncCompletionHandler<Response>(){
50-
51-
@Override
52-
public Response onCompleted(Response response) throws Exception{
53-
// Do something with the Response
54-
// ...
55-
return response;
56-
}
57-
58-
@Override
59-
public void onThrowable(Throwable t){
60-
// Something wrong happened.
61-
}
62-
});
37+
import static org.asynchttpclient.Dsl.*;
38+
39+
AsyncHttpClient asyncHttpClient = asyncHttpClient();
6340
```
6441

65-
(this will also fully read `Response` in memory before calling `onCompleted`)
42+
AsyncHttpClient instances must be closed (call the `close` method) once you're done with them, typically when shutting down your application.
43+
If you don't, you'll experience threads hanging and resource leaks.
44+
45+
AsyncHttpClient instances are intended to be global resources that share the same lifecycle as the application.
46+
Typically, AHC will usually underperform if you create a new client for each request, as it will create new threads and connection pools for each.
47+
It's possible to create shared resources (EventLoop and Timer) beforehand and pass them to multiple client instances in the config. You'll then be responsible for closing those shared resources.
48+
49+
## Configuration
6650

67-
Alternatively you may use continuations (through Java 8 class `CompletableFuture<T>`) to accomplish asynchronous (non-blocking) solution. The equivalent continuation approach to the previous example is:
51+
Finally, you can also configure the AsyncHttpClient instance via its AsyncHttpClientConfig object:
6852

6953
```java
7054
import static org.asynchttpclient.Dsl.*;
7155

56+
AsyncHttpClient c = asyncHttpClient(config().setProxyServer(proxyServer("127.0.0.1", 38080)));
57+
```
58+
59+
## HTTP
60+
61+
### Sending Requests
62+
63+
### Basics
64+
65+
AHC provides 2 APIs for defining requests: bound and unbound.
66+
`AsyncHttpClient` and Dls` provide methods for standard HTTP methods (POST, PUT, etc) but you can also pass a custom one.
67+
68+
```java
7269
import org.asynchttpclient.*;
73-
import java.util.concurrent.CompletableFuture;
7470

75-
AsyncHttpClient asyncHttpClient = asyncHttpClient();
76-
CompletableFuture<Response> promise = asyncHttpClient
77-
.prepareGet("http://www.example.com/")
78-
.execute()
79-
.toCompletableFuture()
80-
.exceptionally(t -> { /* Something wrong happened... */ } )
81-
.thenApply(resp -> { /* Do something with the Response */ return resp; });
82-
promise.join(); // wait for completion
71+
// bound
72+
Future<Response> whenResponse = asyncHttpClient.prepareGet("http://www.example.com/").execute();
73+
74+
// unbound
75+
Request request = get("http://www.example.com/");
76+
Future<Response> whenResponse = asyncHttpClient.executeRequest("http://www.example.com/").execute();
8377
```
8478

85-
You may get the complete maven project for this simple demo from [org.asynchttpclient.example](https://github.com/AsyncHttpClient/async-http-client/tree/master/example/src/main/java/org/asynchttpclient/example)
79+
#### Setting Request Body
80+
81+
Use the `setBody` method to add a body to the request.
82+
83+
This body can be of type:
84+
* `java.io.File`
85+
* `byte[]`
86+
* `List<byte[]>`
87+
* `String`
88+
* `java.nio.ByteBuffer`
89+
* `java.io.InputStream`
90+
* `Publisher<io.netty.bufferByteBuf>`
91+
* `org.asynchttpclient.request.body.generator.BodyGenerator`
92+
93+
`BodyGenerator` is a generic abstraction that let you create request bodies on the fly.
94+
Have a look at `FeedableBodyGenerator` if you're looking for a way to pass requests chunks on the fly.
95+
96+
#### Multipart
8697

87-
You can also mix Future with AsyncHandler to only retrieve part of the asynchronous response
98+
Use the `addBodyPart` method to add a multipart part to the request.
99+
100+
This part can be of type:
101+
* `ByteArrayPart`
102+
* `FilePart`
103+
* `StringPart`
104+
105+
### Dealing with Responses
106+
107+
#### Blocking on the Future
108+
109+
`execute` methods return a `java.util.concurrent.Future`. You can simply both the calling thread to get the response.
88110

89111
```java
90-
import org.asynchttpclient.*;
91-
import java.util.concurrent.Future;
92-
93-
AsyncHttpClient asyncHttpClient = new DefaultAsyncHttpClient();
94-
Future<Integer> f = asyncHttpClient.prepareGet("http://www.example.com/").execute(
95-
new AsyncCompletionHandler<Integer>(){
96-
97-
@Override
98-
public Integer onCompleted(Response response) throws Exception{
99-
// Do something with the Response
100-
return response.getStatusCode();
101-
}
102-
103-
@Override
104-
public void onThrowable(Throwable t){
105-
// Something wrong happened.
106-
}
107-
});
112+
Future<Response> whenResponse = asyncHttpClient.prepareGet("http://www.example.com/").execute();
113+
Response response = whenResponse.get();
114+
```
115+
116+
This is useful for debugging but you'll most likely hurt performance or create bugs when running such code on production.
117+
The point of using a non blocking client is to *NOT BLOCK* the calling thread!
108118

109-
int statusCode = f.get();
119+
### Setting callbacks on the ListenableFuture
120+
121+
`execute` methods actually return a `org.asynchttpclient.ListenableFuture` similar to Guava's.
122+
You can configure listeners to be notified of the Future's completion.
123+
124+
```java
125+
ListenableFuture<Response> whenResponse = ???;
126+
Runnable callback = () -> {
127+
try {
128+
Response response = whenResponse.get();
129+
System.out.println(response);
130+
} catch (InterruptedException | ExecutionException e) {
131+
e.printStackTrace();
132+
}
133+
};
134+
java.util.concurrent.Executor executor = ???;
135+
whenResponse.addListener(() -> ???, executor);
110136
```
111137

112-
which is something you want to do for large responses: this way you can process content as soon as it becomes available, piece by piece, without having to buffer it all in memory.
138+
If the `executor` parameter is null, callback will be executed in the IO thread.
139+
You *MUST NEVER PERFORM BLOCKING* operations in there, typically sending another request and block on a future.
113140

114-
You have full control on the Response life cycle, so you can decide at any moment to stop processing what the server is sending back:
141+
#### Using custom AsyncHandlers
142+
143+
`execute` methods can take an `org.asynchttpclient.AsyncHandler` to be notified on the different events, such as receiving the status, the headers and body chunks.
144+
When you don't specify one, AHC will use a `org.asynchttpclient.AsyncCompletionHandler`;
145+
146+
`AsyncHandler` methods can let you abort processing early (return `AsyncHandler.State.ABORT`) and can let you return a computation result from `onCompleted` that will be used as the Future's result.
147+
See `AsyncCompletionHandler` implementation as an example.
148+
149+
The below sample just capture the response status and skips processing the response body chunks.
150+
151+
Note that returning `ABORT` closed the underlying connection.
115152

116153
```java
117154
import static org.asynchttpclient.Dsl.*;
118-
119155
import org.asynchttpclient.*;
120-
import java.util.concurrent.Future;
121-
122-
AsyncHttpClient c = asyncHttpClient();
123-
Future<String> f = c.prepareGet("http://www.example.com/").execute(new AsyncHandler<String>() {
124-
private ByteArrayOutputStream bytes = new ByteArrayOutputStream();
125-
126-
@Override
127-
public STATE onStatusReceived(HttpResponseStatus status) throws Exception {
128-
int statusCode = status.getStatusCode();
129-
// The Status have been read
130-
// If you don't want to read the headers,body or stop processing the response
131-
if (statusCode >= 500) {
132-
return STATE.ABORT;
133-
}
134-
}
135-
136-
@Override
137-
public STATE onHeadersReceived(HttpResponseHeaders h) throws Exception {
138-
Headers headers = h.getHeaders();
139-
// The headers have been read
140-
// If you don't want to read the body, or stop processing the response
141-
return STATE.ABORT;
142-
}
143-
144-
@Override
145-
public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception {
146-
bytes.write(bodyPart.getBodyPartBytes());
147-
return STATE.CONTINUE;
148-
}
149-
150-
@Override
151-
public String onCompleted() throws Exception {
152-
// Will be invoked once the response has been fully read or a ResponseComplete exception
153-
// has been thrown.
154-
// NOTE: should probably use Content-Encoding from headers
155-
return bytes.toString("UTF-8");
156-
}
157-
158-
@Override
159-
public void onThrowable(Throwable t) {
160-
}
156+
import io.netty.handler.codec.http.HttpHeaders;
157+
158+
Future<Integer> f = asyncHttpClient.prepareGet("http://www.example.com/")
159+
.execute(new AsyncHandler<Integer>() {
160+
private Integer status;
161+
@Override
162+
public State onStatusReceived(HttpResponseStatus responseStatus) throws Exception {
163+
status = responseStatus.getStatusCode();
164+
return State.ABORT;
165+
}
166+
@Override
167+
public State onHeadersReceived(HttpHeaders headers) throws Exception {
168+
return State.ABORT;
169+
}
170+
@Override
171+
public State onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception {
172+
return State.ABORT;
173+
}
174+
@Override
175+
public Integer onCompleted() throws Exception {
176+
return status;
177+
}
178+
@Override
179+
public void onThrowable(Throwable t) {
180+
}
161181
});
162182

163-
String bodyResponse = f.get();
183+
Integer statusCode = f.get();
164184
```
165185

166-
## Configuration
186+
#### Using Continuations
167187

168-
Finally, you can also configure the AsyncHttpClient via its AsyncHttpClientConfig object:
188+
`ListenableFuture` has a `toCompletableFuture` that returns a `CompletableFuture`.
189+
Beware that canceling this `CompletableFuture` won't properly cancel the ongoing request.
190+
There's a very good chance we'll return a `CompletionStage` instead in the next release.
169191

170192
```java
171-
AsyncHttpClientConfig cf = new DefaultAsyncHttpClientConfig.Builder()
172-
.setProxyServer(new ProxyServer.Builder("127.0.0.1", 38080)).build();
173-
174-
AsyncHttpClient c = new DefaultAsyncHttpClient(cf);
193+
CompletableFuture<Response> promise = asyncHttpClient
194+
.prepareGet("http://www.example.com/")
195+
.execute()
196+
.toCompletableFuture()
197+
.exceptionally(t -> { /* Something wrong happened... */ } )
198+
.thenApply(resp -> { /* Do something with the Response */ return resp; });
199+
promise.join(); // wait for completion
175200
```
176201

202+
You may get the complete maven project for this simple demo from [org.asynchttpclient.example](https://github.com/AsyncHttpClient/async-http-client/tree/master/example/src/main/java/org/asynchttpclient/example)
203+
177204
## WebSocket
178205

179-
Async Http Client also supports WebSocket by simply doing:
206+
Async Http Client also supports WebSocket.
207+
You need to pass a `WebSocketUpgradeHandler` where you would register a `WebSocketListener`.
180208

181209
```java
182-
WebSocket websocket = c.prepareGet(getTargetUrl())
210+
WebSocket websocket = c.prepareGet("ws://demos.kaazing.com/echo")
183211
.execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(
184-
new WebSocketTextListener() {
185-
186-
@Override
187-
public void onMessage(String message) {
188-
}
212+
new WebSocketListener() {
189213

190214
@Override
191215
public void onOpen(WebSocket websocket) {
@@ -194,7 +218,11 @@ WebSocket websocket = c.prepareGet(getTargetUrl())
194218

195219
@Override
196220
public void onClose(WebSocket websocket) {
197-
latch.countDown();
221+
}
222+
223+
@Override
224+
public void onTextFrame(String payload, boolean finalFragment, int rsv) {
225+
System.out.println(payload);
198226
}
199227

200228
@Override
@@ -203,6 +231,41 @@ WebSocket websocket = c.prepareGet(getTargetUrl())
203231
}).build()).get();
204232
```
205233

234+
## Reactive Streams
235+
236+
AsyncHttpClient has build in support for reactive streams.
237+
238+
You can pass a request body as a `Publisher<ByteBuf>` or a `ReactiveStreamsBodyGenerator`.
239+
240+
You can also pass a `StreamedAsyncHandler<T>` whose `onStream` method will be notified with a `Publisher<HttpResponseBodyPart>`.
241+
242+
See tests in package `org.asynchttpclient.reactivestreams` for examples.
243+
244+
## WebDAV
245+
246+
AsyncHttpClient has build in support for the WebDAV protocol.
247+
The API can be used the same way normal HTTP request are made:
248+
249+
```java
250+
Request mkcolRequest = new RequestBuilder("MKCOL").setUrl("http://host:port/folder1").build();
251+
Response response = c.executeRequest(mkcolRequest).get();
252+
```
253+
or
254+
255+
```java
256+
Request propFindRequest = new RequestBuilder("PROPFIND").setUrl("http://host:port).build();
257+
Response response = c.executeRequest(propFindRequest, new AsyncHandler(){...}).get();
258+
```
259+
260+
## More
261+
262+
You can find more information on Jean-François Arcand's blog. Jean-François is the original author of this library.
263+
Code is sometimes not up-to-date but gives a pretty good idea of advanced features.
264+
265+
* https://jfarcand.wordpress.com/2010/12/21/going-asynchronous-using-asynchttpclient-the-basic/
266+
* https://jfarcand.wordpress.com/2011/01/04/going-asynchronous-using-asynchttpclient-the-complex/
267+
* https://jfarcand.wordpress.com/2011/12/21/writing-websocket-clients-using-asynchttpclient/
268+
206269
## User Group
207270
208271
Keep up to date on the library development by joining the Asynchronous HTTP Client discussion group

0 commit comments

Comments
 (0)