Suivez @AsyncHttpClient sur Twitter.
La bibliothèque AsyncHttpClient (AHC) permet aux applications Java d'exécuter facilement des requêtes HTTP et de traiter de manière asynchrone les réponses HTTP. La bibliothèque prend également en charge le protocole WebSocket.
Il est construit sur Netty. Il est compilé avec Java 11.
Les binaires sont déployés sur Maven Central. Ajoutez une dépendance sur l'artefact principal AsyncHttpClient :
Maven :
< dependencies >
< dependency >
< groupId >org.asynchttpclient</ groupId >
< artifactId >async-http-client</ artifactId >
< version >3.0.1</ version >
</ dependency >
</ dependencies >
Graduation :
dependencies {
implementation ' org.asynchttpclient:async-http-client:3.0.1 '
}
Importez les assistants DSL pour utiliser des méthodes pratiques pour amorcer les composants :
import static org . asynchttpclient . Dsl .*;
import static org . asynchttpclient . Dsl .*;
AsyncHttpClient asyncHttpClient = asyncHttpClient ();
Les instances AsyncHttpClient doivent être fermées (appelez la méthode close
) une fois que vous en avez terminé, généralement lors de la fermeture de votre application. Si vous ne le faites pas, vous rencontrerez des blocages de threads et des fuites de ressources.
Les instances AsyncHttpClient sont destinées à être des ressources globales partageant le même cycle de vie que l'application. En règle générale, AHC sera généralement sous-performant si vous créez un nouveau client pour chaque requête, car il créera de nouveaux threads et pools de connexions pour chacun. Il est possible de créer au préalable des ressources partagées (EventLoop et Timer) et de les transmettre à plusieurs instances client dans la configuration. Vous serez ensuite responsable de la fermeture de ces ressources partagées.
Enfin, vous pouvez également configurer l'instance AsyncHttpClient via son objet AsyncHttpClientConfig :
import static org . asynchttpclient . Dsl .*;
AsyncHttpClient c = asyncHttpClient ( config (). setProxyServer ( proxyServer ( "127.0.0.1" , 38080 )));
AHC fournit 2 API pour définir les requêtes : liées et non liées. AsyncHttpClient
et Dsl` fournissent des méthodes pour les méthodes HTTP standard (POST, PUT, etc.), mais vous pouvez également en transmettre une personnalisée.
import org . asynchttpclient .*;
// bound
Future < Response > whenResponse = asyncHttpClient . prepareGet ( "http://www.example.com/" ). execute ();
// unbound
Request request = get ( "http://www.example.com/" ). build ();
Future < Response > whenResponse = asyncHttpClient . executeRequest ( request );
Utilisez la méthode setBody
pour ajouter un corps à la requête.
Ce corps peut être de type :
java.io.File
byte[]
List<byte[]>
String
java.nio.ByteBuffer
java.io.InputStream
Publisher<io.netty.buffer.ByteBuf>
org.asynchttpclient.request.body.generator.BodyGenerator
BodyGenerator
est une abstraction générique qui vous permet de créer des corps de requête à la volée. Jetez un œil à FeedableBodyGenerator
si vous cherchez un moyen de transmettre des morceaux de requêtes à la volée.
Utilisez la méthode addBodyPart
pour ajouter une partie en plusieurs parties à la demande.
Cette pièce peut être de type :
ByteArrayPart
FilePart
InputStreamPart
StringPart
Les méthodes execute
renvoient un java.util.concurrent.Future
. Vous pouvez simplement bloquer le thread appelant pour obtenir la réponse.
Future < Response > whenResponse = asyncHttpClient . prepareGet ( "http://www.example.com/" ). execute ();
Response response = whenResponse . get ();
Ceci est utile pour le débogage, mais vous risquez très probablement de nuire aux performances ou de créer des bogues lors de l'exécution d'un tel code en production. L’intérêt d’utiliser un client non bloquant est de NE PAS BLOQUER le thread appelant !
Les méthodes execute
renvoient en fait un org.asynchttpclient.ListenableFuture
similaire à celui de Guava. Vous pouvez configurer les auditeurs pour qu'ils soient informés de l'achèvement du Future.
ListenableFuture < Response > whenResponse = ???;
Runnable callback = () - > {
try {
Response response = whenResponse . get ();
System . out . println ( response );
} catch ( InterruptedException | ExecutionException e ) {
e . printStackTrace ();
}
};
java . util . concurrent . Executor executor = ???;
whenResponse . addListener (() - > ??? , executor );
Si le paramètre executor
est nul, le rappel sera exécuté dans le thread IO. Vous NE DEVEZ JAMAIS EFFECTUER d'opérations de BLOCAGE à cet endroit, généralement en envoyant une autre requête et en bloquant un futur.
Les méthodes execute
peuvent prendre un org.asynchttpclient.AsyncHandler
pour être averti des différents événements, tels que la réception du statut, des en-têtes et des morceaux de corps. Lorsque vous n'en spécifiez pas, AHC utilisera un org.asynchttpclient.AsyncCompletionHandler
;
Les méthodes AsyncHandler
peuvent vous permettre d'abandonner le traitement plus tôt (retourner AsyncHandler.State.ABORT
) et vous permettre de renvoyer un résultat de calcul à partir de onCompleted
qui sera utilisé comme résultat de Future. Voir l’implémentation AsyncCompletionHandler
à titre d’exemple.
L'exemple ci-dessous capture simplement l'état de la réponse et ignore le traitement des morceaux du corps de la réponse.
Notez que le retour de ABORT
ferme la connexion sous-jacente.
import static org . asynchttpclient . Dsl .*;
import org . asynchttpclient .*;
import io . netty . handler . codec . http . HttpHeaders ;
Future < Integer > whenStatusCode = asyncHttpClient . prepareGet ( "http://www.example.com/" )
. execute ( new AsyncHandler < Integer > () {
private Integer status ;
@ Override
public State onStatusReceived ( HttpResponseStatus responseStatus ) throws Exception {
status = responseStatus . getStatusCode ();
return State . ABORT ;
}
@ Override
public State onHeadersReceived ( HttpHeaders headers ) throws Exception {
return State . ABORT ;
}
@ Override
public State onBodyPartReceived ( HttpResponseBodyPart bodyPart ) throws Exception {
return State . ABORT ;
}
@ Override
public Integer onCompleted () throws Exception {
return status ;
}
@ Override
public void onThrowable ( Throwable t ) {
t . printStackTrace ();
}
});
Integer statusCode = whenStatusCode . get ();
ListenableFuture
a une méthode toCompletableFuture
qui renvoie un CompletableFuture
. Attention, l'annulation de ce CompletableFuture
n'annulera pas correctement la demande en cours. Il y a de très fortes chances que nous renvoyions un CompletionStage
à la place dans la prochaine version.
CompletableFuture < Response > whenResponse = asyncHttpClient
. prepareGet ( "http://www.example.com/" )
. execute ()
. toCompletableFuture ()
. exceptionally ( t ->{ /* Something wrong happened... */ })
. thenApply ( response ->{ /* Do something with the Response */ return resp ;});
whenResponse . join (); // wait for completion
Vous pouvez obtenir le projet Maven complet pour cette démo simple à partir de org.asynchttpclient.example
Le client HTTP asynchrone prend également en charge WebSocket. Vous devez transmettre un WebSocketUpgradeHandler
où vous enregistreriez un WebSocketListener
.
WebSocket websocket = c . prepareGet ( "ws://demos.kaazing.com/echo" )
. execute ( new WebSocketUpgradeHandler . Builder (). addWebSocketListener (
new WebSocketListener () {
@ Override
public void onOpen ( WebSocket websocket ) {
websocket . sendTextFrame ( "..." ). sendTextFrame ( "..." );
}
@ Override
public void onClose ( WebSocket websocket ) {
// ...
}
@ Override
public void onTextFrame ( String payload , boolean finalFragment , int rsv ) {
System . out . println ( payload );
}
@ Override
public void onError ( Throwable t ) {
t . printStackTrace ();
}
}). build ()). get ();
Tenez-vous au courant du développement de la bibliothèque en rejoignant le groupe de discussion sur le client HTTP asynchrone.
Discussions sur GitHub