Asynchrone client HTTP avec Netty
Je suis nouveau sur netty et encore strugling de trouver mon chemin. Je suis à la recherche pour créer un client http qui fonctionne de manière asynchrone.
Le netty exemples de http seulement de montrer comment attendre pour les opérations d'e /s, et non pas comment l'utiliser addListener, et j'ai donc été d'essayer de comprendre cela pour les derniers jours.
Je suis en train de créer une classe de requête qui va gérer tous les différents états d'une demande, à partir de la connexion, de l'envoi des données, la manipulation de la réponse, puis la fermeture de la connexion.
Dans le but de faire que les élèves de ma classe s'étend SimpleChannelUpstreamHandler et met en œuvre ChannelFutureListener. J'utilise un ChannelPipelineFactory qui ajoute de l' (ce) de l'instance de la classe (comme un SimpleChannelUpstreamHandler) pour le pipeline en tant que gestionnaire.
La connexion est créée comme ceci:
this.state = State.Connecting;
this.clientBootstrap.connect(this.address).addListener(this);
Puis le operationComplete méthode:
@Override
public void operationComplete(ChannelFuture future) throws Exception {
State oldState = this.state;
if (!future.isSuccess()) {
this.status = Status.Failed;
future.getChannel().disconnect().addListener(this);
}
else if (future.isCancelled()) {
this.status = Status.Canceled;
future.getChannel().disconnect().addListener(this);
}
else switch (this.state) {
case Connecting:
this.state = State.Sending;
Channel channel = future.getChannel();
channel.write(this.createRequest()).addListener(this);
break;
case Sending:
this.state = State.Disconnecting;
future.getChannel().disconnect().addListener(this);
break;
case Disconnecting:
this.state = State.Closing;
future.getChannel().close().addListener(this);
break;
case Closing:
this.state = State.Finished;
break;
}
System.out.println("request operationComplete start state: " + oldState + ", end state: " + this.state + ", status: " + this.status);
}
private HttpRequest createRequest() {
String url = this.url.toString();
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, url);
request.setHeader(HttpHeaders.Names.HOST, this.url.getHost());
request.setHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE);
request.setHeader(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP);
return request;
}
La classe remplace également le messageReceived méthode:
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
System.out.println("messageReceived");
HttpResponse response = (HttpResponse) e.getMessage();
ChannelBuffer content = response.getContent();
if (content.readable()) {
System.out.println("CONTENT: " + content.toString(CharsetUtil.UTF_8));
}
}
Le problème est que j'obtiens ce résultat:
request operationComplete start state: Connecting, end state: Sending, status: Unknown
request operationComplete start state: Sending, end state: Disconnecting, status: Unknown
request operationComplete start state: Closing, end state: Finished, status: Unknown
request operationComplete start state: Disconnecting, end state: Finished, status: Unknown
Comme vous pouvez le voir le messageReceived de la n'est pas exécuté pour une raison quelconque, même si le pipeline d'usine, ajoute l'instance de cette classe pour le pipeline.
Les idées de ce que je suis en manque ici?
Merci.
Modifier
J'ai réussi à obtenir enfin ce travail grâce à l'aide de @JestanNirojan, au cas où quelqu'un sera intéressé par la solution:
public class ClientRequest extends SimpleChannelUpstreamHandler {
....
public void connect() {
this.state = State.Connecting;
System.out.println(this.state);
this.clientBootstrap.connect(this.address);
}
@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
this.state = State.Sending;
System.out.println(this.state);
ctx.getChannel().write(this.createRequest());
}
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
HttpResponse response = (HttpResponse) e.getMessage();
ChannelBuffer content = response.getContent();
if (content.readable()) {
System.out.println("CONTENT: " + content.toString(CharsetUtil.UTF_8));
}
this.state = State.Disconnecting;
System.out.println(this.state);
}
@Override
public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
this.state = State.Closing;
System.out.println(this.state);
}
@Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
this.state = State.Finished;
System.out.println(this.state);
}
private HttpRequest createRequest() {
String url = this.url.toString();
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, url);
request.setHeader(HttpHeaders.Names.HOST, this.url.getHost());
request.setHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE);
request.setHeader(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP);
return request;
}
}
Le HttpResponse est la réponse complète, vous ne pouvez pas morceau d'aussi loin que je sache. Vous devriez aller plus bas alors que, probablement avec HttpResponseDecoder.
Si vous n'êtes pas interessé dans le chunking utiliser la lumière http client ici @ github.com/arungeorge81/netty-http-client
OriginalL'auteur Nitzan Tomer | 2012-03-16
Vous devez vous connecter pour publier un commentaire.
Vous utilisez un ChannelFutureListener de faire toutes les opérations dans le canal (qui est mauvais), et le futur auditeur sera exécuté juste après l'appel de ces opérations de la manche.
Le problème est, Après l'envoi du message, le canal est immédiatement déconnecté et le gestionnaire ne peut pas recevoir le message de réponse qui vient plus tard.
vous ne devez pas bloquer le canal de l'avenir thread à tous. La meilleure approche est d'étendre le SimpleChannelUpstreamHandler de
méthodes et de réagir à ces événements. vous pouvez conserver l'état dans ce gestionnaire de trop.
OriginalL'auteur Jestan Nirojan