下面是开发基于Netty的HTTP/HTTPS应用程序的完整攻略:
1. 环境准备
- JDK 1.8及以上版本
- Maven 3.0及以上版本
- Netty 4.1.32.Final及以上版本
2. 创建maven项目
使用Maven创建一个新的项目,添加Netty以及其他必要的依赖:
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.32.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId>
<version>4.1.32.Final</version>
</dependency>
<!--其他必要依赖,例如log等-->
</dependencies>
3. 编写HTTP服务器
创建HTTP服务器的代码如下所示:
public class HttpServer {
private final int port;
public HttpServer(int port) {
this.port = port;
}
public void start() throws Exception {
// EventLoopGroup是用来处理IO操作的多线程事件循环器
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
// ServerBootstrap 是一个启动 NIO 服务的辅助启动类
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class) // 使用N//IO模型
.localAddress(new InetSocketAddress(port))
.childHandler(new HttpServerInitializer()); // 指定 childHandler 处理请求
// 服务器异步创建绑定
ChannelFuture future = bootstrap.bind().sync();
// 关闭服务器通道
future.channel().closeFuture().sync();
} finally {
// 释放线程池资源,优雅关闭
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port = 8888;
HttpServer server = new HttpServer(port);
server.start();
}
}
在上面代码中,我们继承了io.netty.channel.ChannelInitializer
类来对请求进行处理,这是一个自定义的HttpServerInitializer
类如下:
public class HttpServerInitializer extends ChannelInitializer<SocketChannel> {
/**
* 服务端读到请求后,需要做的初始化
*/
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast("httpServerCodec", new HttpServerCodec());
pipeline.addLast("httpObjectAggregator", new HttpObjectAggregator(65536)); // 将多个消息转换成单一 FullHttpRequest 或 FullHttpResponse
pipeline.addLast("httpServerHandler", new HttpServerHandler());
}
}
上面代码中,我们主要添加了三个handler处理器,HttpServerCodec
是对发送到服务端的请求进行编码,HttpObjectAggregator
将多个请求合并成一个请求,而HttpServerHandler
是HTTP服务端响应请求的具体业务处理。
HttpServerHandler
的业务处理代码如下:
public class HttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
// 发送HTTP响应
StringBuilder responseContent = new StringBuilder();
responseContent.append("<html>\r\n");
responseContent.append("<head><title>Netty Http Server</title></head>\r\n");
responseContent.append("<body>\r\n");
responseContent.append("<h3>Hello, World!</h3>\r\n");
// 处理 GET 请求
if (request.method().equals(HttpMethod.GET)) {
QueryStringDecoder decoder = new QueryStringDecoder(request.uri());
String param = decoder.parameters().get("param").get(0);
responseContent.append("<p>GET Request param: ").append(param).append("</p>\r\n");
}
// 处理 POST 请求
if (request.method().equals(HttpMethod.POST)) {
String param = request.content().toString(CharsetUtil.UTF_8);
responseContent.append("<p>POST Request param: ").append(param).append("</p>\r\n");
}
responseContent.append("</body>\r\n");
responseContent.append("</html>\r\n");
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
Unpooled.copiedBuffer(responseContent.toString(), CharsetUtil.UTF_8));
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html;charset=UTF-8");
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
}
}
上面代码中,我们对GET和POST请求进行了处理,并返回了一个简单的HTML页面。
4. 编写HTTPS服务器
创建HTTPS服务器的步骤基本上和创建HTTP服务器类似,唯一不同的在于我们需要使用SSL认证。下面是HTTPS服务器代码的示例:
public class HttpsServer {
private final int port;
public HttpsServer(int port) {
this.port = port;
}
public void start() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
// 配置SSL
SslContext sslCtx = SslContextBuilder.forServer(getKeyStore(), "123456")
.trustManager(getTrustManagerFactory())
.build();
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(port))
.childHandler(new HttpsServerInitializer(sslCtx));
ChannelFuture f = b.bind().sync();
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port = 8443;
HttpsServer server = new HttpsServer(port);
server.start();
}
private static KeyStore getKeyStore() throws Exception {
String userHome = System.getProperty("user.home");
try (InputStream keyStoreStream = new FileInputStream(userHome + "/.keystore")) {
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(keyStoreStream, "123456".toCharArray());
return keyStore;
}
}
private static TrustManagerFactory getTrustManagerFactory() throws Exception {
KeyStore keyStore = getKeyStore();
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
return trustManagerFactory;
}
}
在上面代码中,我们添加了一个HttpsServerInitializer
类来对HTTPS请求进行处理:
public class HttpsServerInitializer extends ChannelInitializer<SocketChannel> {
private final SslContext sslCtx;
public HttpsServerInitializer(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("ssl", sslCtx.newServerContext().newHandler(ch.alloc()));
pipeline.addLast("httpServerCodec", new HttpServerCodec());
pipeline.addLast("httpObjectAggregator", new HttpObjectAggregator(65536));
pipeline.addLast("httpServerHandler", new HttpServerHandler());
}
}
在上面代码中,我们添加了一个sslContext
作为HTTPS认证所需的上下文,其中需要包含证书、私钥等信息。我们创建了HttpsServerInitializer
类来对接收到的HTTPS请求进行处理。
5. 示例说明
下面是两个示例,分别针对HTTP和HTTPS请求进行处理。
- 处理GET请求:
假设我们的服务器地址为:http://localhost:8888?param=abc
。发送一个GET请求时,我们会从HttpServerHandler
中的代码中获取到?param=abc
这个参数,并将参数返回显示在响应页面中。
- 处理POST请求:
假设我们的服务器地址为:http://localhost:8888
。发送一个POST请求时,我们可以在请求体中添加参数,例如param1=xxx¶m2=yyy
,然后服务器会将参数解析出来,并将它们返回显示在响应页面中。
至此,我们已经完整地实现了基于Netty的HTTP/HTTPS应用程序攻略,您可以根据自己需要进行适当地调整。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:如何开发基于Netty的HTTP/HTTPS应用程序 - Python技术站