[英]Asynchronous HTTP client with Netty
我是netty的新手,仍然喜歡找我的路。 我正在尋找創建一個異步工作的http客戶端。 http的netty示例僅顯示如何等待IO操作,而不是如何使用addListener ,因此我一直試圖在過去幾天解決這個問題。
我正在嘗試創建一個請求類,它將處理請求的所有不同狀態,包括連接,發送數據,處理響應,然后關閉連接。 為了做到這一點,我的類擴展了SimpleChannelUpstreamHandler並實現了ChannelFutureListener 。 我使用ChannelPipelineFactory將類(作為SimpleChannelUpstreamHandler )的(this)實例作為處理程序添加到管道。
連接創建如下:
this.state = State.Connecting;
this.clientBootstrap.connect(this.address).addListener(this);
然后是operationComplete方法:
@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;
}
該類還會覆蓋messageReceived方法:
@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));
}
}
問題是我得到了這個輸出:
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
正如您所看到的,由於某種原因,即使管道工廠將此類的實例添加到管道中,因此仍未執行messageReceived 。
我在這里缺少什么想法? 謝謝。
在@JestanNirojan的幫助下,我終於得到了這個工作,以防有人對該解決方案感興趣:
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;
}
}
您正在使用ChannelFutureListener來執行通道中的所有操作(這是錯誤的),並且將在調用這些通道操作后立即執行將來的偵聽器。
問題是,在發送消息后,通道立即斷開,處理程序無法接收稍后出現的響應消息。
........
case Sending:
this.state = State.Disconnecting;
future.getChannel().disconnect().addListener(this);
break;
........
你不應該阻止頻道未來的線程。 最好的方法是擴展SimpleChannelUpstreamHandler
channelConnected(..) {}
messageReceived(..) {}
channelDisconnected(..) {}
方法並對這些事件做出反應。 你也可以把狀態保持在那個處理程序中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.