2013-04-02 35 views
0

這與this question有關,但我試圖將我的問題分解成更小的步驟。如何解碼來自http請求的響應並使用netty中的內容?

我試圖寫一個簡單的http服務器使用接收HTTP請求網狀(服務器A),發出HTTP請求到另一臺服務器(服務器B),然後複製在響應到響應於內容最初的請求。我知道這裏有一些例子,比如LittleProxy,但是代碼相當複雜,而且因爲我是netb的n00b,所以我試圖儘可能簡單地使我的第一個代碼不會進入雜草。現在,我忽略了關於併發性的所有問題,並且只有一個通道從服務器A建立到服務器B(我知道這會與併發請求發生可怕的衝突,但它使我的初始任務更簡單)。

我的做法是這樣的:

  1. 設置客戶端引導並連接到本地主機端口18080.上運行的服務器B獲取相應的通道。

  2. 啓動服務器的端口2080與管道解碼的HTTP請求,然後聽音寫入通道將服務器B.

  3. 添加監聽器所產生的通道未來將複製的內容從服務器B響應到原始客戶端的請求到服務器A.

這裏的響應是在我試圖做的正是我所描述上面的代碼我有(很短)。我的問題是,我不知道如何將響應從服務器B複製到服務器的響應。當我在服務器A發送的響應(我檢查了ChannelBuffer的內容,並且被代理服務器返回了正確的文本)的響應中寫入原始客戶端時,我發現要做到這一點的方式會導致IllegalArgumentException。我粘貼了下面例外的部分堆棧跟蹤。其他意見歡迎,因爲有可能是我做除了明顯缺乏鎖定通道到服務器B上的其他錯誤:

public class NettyExample { 

private static Channel channel; 
private static Map<Channel, Channel> proxyToClient = new ConcurrentHashMap<Channel, Channel>(); 

public static void main(String[] args) throws Exception { 
    ChannelFactory clientFactory = 
      new NioClientSocketChannelFactory(
        Executors.newCachedThreadPool(), 
        Executors.newCachedThreadPool()); 
    final ClientBootstrap cb = new ClientBootstrap(clientFactory); 
    cb.setPipelineFactory(new ChannelPipelineFactory() { 
     public ChannelPipeline getPipeline() { 
      return Channels.pipeline(
        new HttpRequestEncoder(), 
        new HttpResponseDecoder(), 
        new ResponseHandler()); 
     } 
    }); 
    ChannelFuture cf = cb.connect(new InetSocketAddress("localhost", 18080)); 
    channel = cf.awaitUninterruptibly().getChannel(); 

    ChannelFactory factory = 
      new NioServerSocketChannelFactory(
        Executors.newCachedThreadPool(), 
        Executors.newCachedThreadPool()); 
    ServerBootstrap sb = new ServerBootstrap(factory); 

    sb.setPipelineFactory(new ChannelPipelineFactory() { 
     public ChannelPipeline getPipeline() { 
      return Channels.pipeline(
        new HttpRequestDecoder(), 
        new RequestHandler()); 
     } 
    }); 

    sb.setOption("child.tcpNoDelay", true); 
    sb.setOption("child.keepAlive", true); 

    sb.bind(new InetSocketAddress(2080)); 
} 

private static class ResponseHandler extends SimpleChannelHandler { 

    @Override 
    public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e) { 
     final HttpResponse proxyResponse = (HttpResponse) e.getMessage(); 
     Channel clientChannel = proxyToClient.get(e.getChannel()); 
     HttpResponse clientResponse = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); 
     clientResponse.setContent(proxyResponse.getContent()); 
     clientChannel.write(clientResponse).addListener(new ChannelFutureListener() { 
      public void operationComplete(ChannelFuture future) { 
       Channel ch = future.getChannel(); 
       ch.close(); 
      } 
     }); 
    } 

    @Override 
    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) { 
     e.getCause().printStackTrace(); 
     Channel ch = e.getChannel(); 
     ch.close(); 
    } 
} 

private static class RequestHandler extends SimpleChannelHandler { 

    @Override 
    public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e) { 
     final HttpRequest request = (HttpRequest) e.getMessage(); 
     System.out.println("calling client channel"); 
     proxyToClient.put(channel, e.getChannel()); 
     channel.write(request); 
    } 

    @Override 
    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) { 
     e.getCause().printStackTrace(); 
     Channel ch = e.getChannel(); 
     ch.close(); 
    } 
} 
} 

此中繼呼叫似乎工作,直至調用clientChannel.write點(clientResponse)。在那裏,會產生以下異常:

java.lang.IllegalArgumentException: unsupported message type: class org.jboss.netty.handler.codec.http.DefaultHttpResponse 
    at org.jboss.netty.channel.socket.nio.SocketSendBufferPool.acquire(SocketSendBufferPool.java:53) 
    at org.jboss.netty.channel.socket.nio.AbstractNioWorker.write0(AbstractNioWorker.java:468) 
    at org.jboss.netty.channel.socket.nio.AbstractNioWorker.writeFromTaskLoop(AbstractNioWorker.java:432) 

回答

3

您需要設置客戶端管道以等待響應,然後將其寫爲響應。

查看snoop客戶端example;具體而言,HttpSnoopClientHandler

+0

謝謝!編寫DefaultHttpResponse到通道仍然有問題。我不知道爲什麼它不適合我的情況。我已經編輯了上面的問題來反映這一點,並提出了一個單獨的問題(http://stackoverflow.com/questions/15795061/unable-to-write-defaulthttpresponse-to-a-channel-in-netty-unsupported-message )具體關於這個。 – jonderry

相關問題