Netty学习——用Netty实现一个简单的Http服务器

            用Netty实现一个简单的Http服务器

      Netty默认实现了Http的请求解析与响应封装,可以很方便地利用这些已经利用好的处理器来实现一个简单的Http服务器,或者自己实现更加复杂的Http服务器逻辑。下面是我用Netty实现的一个可以接收Http get或post请求的http服务器,并且可以解析出请求参数,然后生成一个页面,显示出请求参数。
package study.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpRequestEncoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.util.CharsetUtil;

public class NettyHttpServer {
public static void main(String[] args) {
	EventLoopGroup bossGroup = new NioEventLoopGroup();
	EventLoopGroup workerGroup = new NioEventLoopGroup();
	ServerBootstrap bootstrap = new ServerBootstrap();
	bootstrap.group(bossGroup, workerGroup)
	.option(ChannelOption.SO_BACKLOG, 1024)
	.channel(NioServerSocketChannel.class)
	.childHandler(new ChannelInitializer() {

		@Override
		protected void initChannel(SocketChannel ch) throws Exception {
			ch.pipeline().addLast("http-decoder",new HttpRequestDecoder());
			ch.pipeline().addLast("http-aggregator",new HttpObjectAggregator(65535));//将多个消息转化成一个
			ch.pipeline().addLast("http-encoder",new HttpResponseEncoder());
			ch.pipeline().addLast("http-chunked",new ChunkedWriteHandler());//解决大码流的问题
			ch.pipeline().addLast("http-server",new HttpHandler());
		}
	});
	ChannelFuture future = bootstrap.bind("localhost",8888);
	try {
		future.channel().closeFuture().sync();
	} catch (InterruptedException e) {
		e.printStackTrace();
	}finally {
		bossGroup.shutdownGracefully();
		workerGroup.shutdownGracefully();
	}
}
	private static class HttpHandler extends SimpleChannelInboundHandler{

		@Override
		protected void messageReceived(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
			try {
			ByteBuf content = msg.content();
			byte[] bts = new byte[content.readableBytes()];
			content.readBytes(bts);
			String result = null;
			if(msg.getMethod() == HttpMethod.GET) {
				String url = msg.getUri().toString();
				result = "get method and paramters is "+ url.substring(url.indexOf("?")+1);
			}else if(msg.getMethod() == HttpMethod.POST) {
				result = "post method and paramters is "+ new String(bts);
			}
			FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
			response.headers().set("content-Type","text/html;charset=UTF-8");
			StringBuilder sb = new StringBuilder();
			sb.append("")
						.append("")
							.append("netty http server")
						.append("")
						.append("")
							.append(result)
						.append("")
					.append("\r\n");
			ByteBuf responseBuf = Unpooled.copiedBuffer(sb,CharsetUtil.UTF_8);
			response.content().writeBytes(responseBuf);
			responseBuf.release();
			ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
			}catch (Exception e) {
				e.printStackTrace();
			}
		}
		
	}
}
跟前面的服务器-客户端通信的例子大同小异,也是添加两个EventLoopGroup,然后创建一个ServerBootstrap,再把两个EventLoopGroup注册到ServerBootstrap中,添加相应的参数,实现SocketChannel初始化器,然后添加相应的处理器,处理器的功能就是相应注释的说明。在继承自SimpleChannelInboundHandler的类中实现自己的处理请求的业务功能,如果是get请求,那么参数就是请求的URI中,解析出?后面的就是请求参数,如果是post请求,那么请求参数就是请求体中,通过获取resquest的content,得到一个缓冲对象,然后把这个缓冲对象中的数据提取出来就解析出了post请求的请求参数。再然后构造一个DefaultFullHttpResponse对象,向这个response的响应体中写入页面的数据,最后调用ctx的writeAndFlush把response对象写回给请求客户端,并添加CLOSE监听,如果不添加的话,Netty就不能知道请求的业务逻辑是否已经结束,也就不知道是否应该结束http的一次请求会话。程序的执行结果就是无论是get请求还是post请求,返回都面都可以返回请求的方法类型还有请求的参数。
      通过使用Netty来构造一个Http WebServer是如此之简单方便,在代码中甚至都没有使用到线程,这是因为Netty在底层已经封装得非常好了,我们使用者几乎可以完全专注于业务逻辑的实现,并且由于Netty的架构设计非常好,对于应用的扩展也是非常的方便,实现一个Http WebServer只需要添加相应的处理器就可以了。如果多的Java网络应用选择Netty作为底层组件不是没有道理的。

你可能感兴趣的:(javaweb,学习,读书笔记)