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

23 篇文章 1 订阅
14 篇文章 0 订阅

            用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<SocketChannel>() {

		@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<FullHttpRequest>{

		@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("<html>")
						.append("<head>")
							.append("<title>netty http server</title>")
						.append("</head>")
						.append("<body>")
							.append(result)
						.append("</body>")
					.append("</html>\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作为底层组件不是没有道理的。
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个使用Netty发送HTTP请求的Java代码示例: ```java import io.netty.bootstrap.Bootstrap; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.http.DefaultFullHttpRequest; import io.netty.handler.codec.http.HttpClientCodec; import io.netty.handler.codec.http.HttpContent; import io.netty.handler.codec.http.HttpContentDecompressor; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpObject; import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.HttpVersion; import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.util.InsecureTrustManagerFactory; import java.net.URI; import java.net.URISyntaxException; public class NettyHttpClient { private final String host; private final int port; private boolean ssl; private SslContext sslContext; public NettyHttpClient(String host, int port, boolean ssl) { this.host = host; this.port = port; this.ssl = ssl; } public void sendHttpRequest() throws Exception { NioEventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group) .channel(NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) .handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { if (ssl) { sslContext = SslContextBuilder.forClient() .trustManager(InsecureTrustManagerFactory.INSTANCE) .build(); ch.pipeline().addLast(sslContext.newHandler(ch.alloc(), host, port)); } ch.pipeline().addLast(new HttpClientCodec()); ch.pipeline().addLast(new HttpContentDecompressor()); ch.pipeline().addLast(new HttpObjectAggregator(1024 * 1024)); ch.pipeline().addLast(new HttpClientHandler()); } }); ChannelFuture f = b.connect(host, port).sync(); URI uri = new URI("http://" + host + ":" + port + "/"); HttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri.toASCIIString(), Unpooled.EMPTY_BUFFER); request.headers().set(HttpHeaders.Names.HOST, host); request.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE); request.headers().set(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP); f.channel().writeAndFlush(request); f.channel().closeFuture().sync(); } finally { group.shutdownGracefully(); } } private class HttpClientHandler extends SimpleChannelInboundHandler<HttpObject> { @Override protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception { if (msg instanceof HttpResponse) { HttpResponse response = (HttpResponse) msg; System.out.println("Status: " + response.getStatus()); System.out.println("Headers: " + response.headers()); } if (msg instanceof HttpContent) { HttpContent content = (HttpContent) msg; System.out.println("Content: " + content.content().toString(io.netty.util.CharsetUtil.UTF_8)); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } } } ``` 您可以使用以下代码调用该类: ```java NettyHttpClient client = new NettyHttpClient("www.example.com", 80, false); client.sendHttpRequest(); ``` 该类使用Netty框架实现HTTP请求,包括处理SSL连接。在sendHttpRequest()方法中,我们使用NioEventLoopGroup创建一个新的客户端通道,然后使用Bootstrap配置通道和处理程序。我们创建一个DefaultFullHttpRequest实例来表示HTTP请求,并将其发送到服务器。客户端处理程序接收响应并处理响应中的数据。最后,我们关闭通道并优雅地关闭事件循环组。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值