解決用netty去作web服務時,post長度過大的問題

原文地址java

http://my.oschina.net/momohuang/blog/114552 web


先說一下,原本是想本身寫socket ,啓動一個簡單點的web服務用於接收數據的。寫完以後,發現會有各類狀況沒有考慮到的,頗有可能出現問題,並且,太折騰了。因而,就用了netty去其web服務,另外,我也以爲netty基本上是最簡單的web服務了吧,若是童鞋們有其餘推薦的話,就留個言唄。bootstrap


一、server
數組

public class AdminServer {
 protected static final Log log = LogFactory.getLog(AdminServer.class);
 public static void main(String[] args) {
 log.info("start app");
 start(8088);
//		System.out.println("admin start on "+1);
 }


 public static void start(int port) {
 // 配置服務器-使用java線程池做爲解釋線程
 ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
 // 設置 pipeline factory.
 bootstrap.setPipelineFactory(new ServerPipelineFactory());
 // 綁定端口
 bootstrap.bind(new InetSocketAddress(port));
 System.out.println("admin start on "+port);
 ServiceLocator.initServiceLocator();
 }


 private static class ServerPipelineFactory implements
 ChannelPipelineFactory {
 public ChannelPipeline getPipeline() throws Exception {
 // Create a default pipeline implementation.
 ChannelPipeline pipeline = Channels.pipeline();
 pipeline.addLast("decoder", new HttpRequestDecoder());
 pipeline.addLast("encoder", new HttpResponseEncoder());


 //http處理handler
 pipeline.addLast("handler", new AdminServerHandler());
 return pipeline;
 }
 }
}

啓動了服務,綁定了8088端口。安全


二、當客戶端給服務端post數據的時候,若是數據超過50K,這個時候服務端接受到的post內容是空的了。這是由於超過了 服務端默認的post的長度的最大值。服務器

http協議裏邊,原本是沒有對post的長度進行限制,可是,不管是系統層面或者是服務端層面的,都會對post的長度進行限制,這個也有利於網絡安全。
網絡


三、在netty中的解決方法app

private static class ServerPipelineFactory implements
            ChannelPipelineFactory {
        public ChannelPipeline getPipeline() throws Exception {
            // Create a default pipeline implementation.
            ChannelPipeline pipeline = Channels.pipeline();
//			pipeline.addFirst("frameDecoder", new LengthFieldBasedFrameDecoder(100000000,0,4,0,4));
            pipeline.addLast("decoder", new HttpRequestDecoder());
            pipeline.addLast("encoder", new HttpResponseEncoder());
//		         pipeline.addLast("streamer", new ChunkedWriteHandler()); 
                 pipeline.addLast("aggregator", new HttpChunkAggregator(65536));//設置塊的最大字節數
            //http處理handler
            pipeline.addLast("handler", new AdminServerHandler());
            return pipeline;
        }
    }

加上socket

pipeline.addLast("aggregator", new HttpChunkAggregator(65536))

以後,設置默認的chunk最大爲 65536,這樣,就能夠接受最大post的內容大小爲 65536。ide

這樣有一個很差的地方,就是這個大小很差控制,開大了,會浪費空間。而且在接受到的字符串的最後,會出現空白的字符串,這是因爲post的內容長度小於chunk裏邊的ChannelBuffer的數組的大小,程序給予補全。

四、本身設置,本身讀取chunk

加上

pipeline.addLast("streamer", new ChunkedWriteHandler());

設置爲給位 分開一個個chunk去接受信息。

public boolean excuteChunk(ChannelHandlerContext ctx, MessageEvent e)
            throws TooLongFrameException {
        // HttpMessage currentMessage = e.getMessage();

        if (e.getMessage() instanceof HttpMessage) {
            HttpMessage m = (HttpMessage) e.getMessage();
            if (m.isChunked()) {
                // A chunked message - remove 'Transfer-Encoding' header,
                // initialize the cumulative buffer, and wait for incoming
                // chunks.
                List<String> encodings = m
                        .getHeaders(HttpHeaders.Names.TRANSFER_ENCODING);
                encodings.remove(HttpHeaders.Values.CHUNKED);
                if (encodings.isEmpty()) {
                    m.removeHeader(HttpHeaders.Names.TRANSFER_ENCODING);
                }
                m.setContent(ChannelBuffers.dynamicBuffer(e.getChannel()
                        .getConfig().getBufferFactory()));
                this.currentMessage = m;
            } else {
                // Not a chunked message - pass through.
                this.currentMessage = null;
            }
            return false;
        } else if (e.getMessage() instanceof HttpChunk) {
            // Sanity check
            if (currentMessage == null) {
                throw new IllegalStateException("received "
                        + HttpChunk.class.getSimpleName() + " without "
                        + HttpMessage.class.getSimpleName());
            }

            // Merge the received chunk into the content of the current message.
            HttpChunk chunk = (HttpChunk) e.getMessage();
            ChannelBuffer content = currentMessage.getContent();

            if (content.readableBytes() > maxContentLength
                    - chunk.getContent().readableBytes()) {
                throw new TooLongFrameException("HTTP content length exceeded "
                        + maxContentLength + " bytes.");
            }

            content.writeBytes(chunk.getContent());
            if (chunk.isLast()) {
                this.currentMessage = null;
                currentMessage.setHeader(HttpHeaders.Names.CONTENT_LENGTH,
                        String.valueOf(content.readableBytes()));
                return true;
                // Channels.fireMessageReceived(ctx, currentMessage,
                // e.getRemoteAddress());
            }
        }
        return true;
    }

在handle中,本身作處理,接受 整個post過來的數據,而後在整合起來,便可

相關文章
相關標籤/搜索