使用netty创建https服务器

因需要https服务器,准备用netty3.x版本搭建一个https服务器,但是怎么弄都没有搞好.所以就选了netty4.x版本.(netty3.x最低JDK1.5,netty4.x最低JDK1.6).下面介绍下netty4.x搭建https服务器.

1. HTTPS服务器启动类

如果想启动多个服务器可以采用多个线程启动多个端口号

package best.nettyserver.https;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class ActivorHttpsServer {
   
   public static void main(String[] args) {
   	new ActivorHttpsServer().start(9998);
   }
   
   public void start(int port){
       // 创建EventLoopGroup
       EventLoopGroup bossGroup = new NioEventLoopGroup();        //创建BOSS线程组 用于服务端接受客户端的连接
       EventLoopGroup workerGroup = new NioEventLoopGroup();      //创建WORK线程组 用于进行SocketChannel的网络读写
       try {
           // 创建ServerBootStrap实例
           // ServerBootstrap 用于启动NIO服务端的辅助启动类,目的是降低服务端的开发复杂度
           ServerBootstrap b = new ServerBootstrap();
           // 绑定Reactor线程池
           b.group(bossGroup, workerGroup)
                   // 设置并绑定服务端Channel
                   // 指定所使用的NIO传输的Channel
                   .channel(NioServerSocketChannel.class)
                   .option(ChannelOption.SO_BACKLOG, 1024)
                   .childHandler(new HttpsServerInitializer());
           System.out.println("接口"+port+"准备就绪");
           // 绑定端口,同步等待成功
           ChannelFuture future = b.bind(port).sync();
           // 等待服务端监听端口关闭
           future.channel().closeFuture().sync();

       } catch (InterruptedException e) {
           e.printStackTrace();
       } finally {
           // 优雅地关闭
           bossGroup.shutdownGracefully();
           workerGroup.shutdownGracefully();
       }
   }
}

2.初始化服务器参数

配置jks文件路径,配置jks密钥的密码,配置handler处理类

package best.nettyserver.https;

import java.io.FileInputStream;
import java.security.KeyStore;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.ssl.SslHandler;

public class HttpsServerInitializer extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline ph = ch.pipeline();
        //添加sslhandler
        char[] passArray = "999999".toCharArray(); //jks密码
        SSLContext sslContext = SSLContext.getInstance("TLSv1");
        KeyStore ks = KeyStore.getInstance("JKS");
        //加载keytool 生成的文件
        FileInputStream inputStream = new FileInputStream("e:/ysstech.jks");
        ks.load(inputStream, passArray);
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(ks, passArray);
        sslContext.init(kmf.getKeyManagers(), null, null);
        inputStream.close();
        SSLEngine sslEngine = sslContext.createSSLEngine(); 
        sslEngine.setUseClientMode(false);
        ch.pipeline().addLast(new SslHandler(sslEngine));
        //处理http服务的关键handler
        //一个组合的HttpRequestDecoder和HttpResponseEncoder使得服务器端HTTP实现更容易。
        ph.addLast("codec", new HttpServerCodec());
        ph.addLast("aggregator", new HttpObjectAggregator(10*1024*1024));
        ph.addLast("handler", new HttpServerHandler());// 服务端逻辑处理类
    }

}

3. handler处理类

配置post,get请求方法,参数,还可以根据path判断其路径

package best.nettyserver.https;

import java.net.InetAddress;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
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.HttpHeaderNames;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.CharsetUtil;

public class HttpServerHandler extends ChannelInboundHandlerAdapter {

    private String result = "";

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (!(msg instanceof FullHttpRequest)) {
            result = "未知请求!";
            send(ctx, result, HttpResponseStatus.BAD_REQUEST);
            return;
        }
        FullHttpRequest httpRequest = (FullHttpRequest) msg;
        try {
            String path = httpRequest.uri();          //获取路径 uri路径,可以根据 这个判断请求接口
            String body = getBody(httpRequest);     //获取参数
            HttpMethod method = httpRequest.method();//获取请求方法
            System.out.println("接收到:" + method + " 请求");
            //如果是GET请求
            if (HttpMethod.GET.equals(method)) {
                //接受到的消息,做业务逻辑处理...
                System.out.println("body:" + body);
                result = "GET请求";
                send(ctx, result, HttpResponseStatus.OK);
                return;
            }
            //如果是POST请求
            if (HttpMethod.POST.equals(method)) {
                //接受到的消息,做业务逻辑处理...
                System.out.println("body:" + body);
                result = "POST请求";
                send(ctx, result, HttpResponseStatus.OK);
                return;
            }
        } catch (Exception e) {
            System.out.println("处理请求失败!");
            e.printStackTrace();
        } finally {
            //释放请求
            httpRequest.release();
        }
    }

    /**
     * 获取body参数
     */
    private String getBody(FullHttpRequest request) {
        ByteBuf buf = request.content();
        return buf.toString(CharsetUtil.UTF_8);
    }

    /**
     * 发送的返回值
     */
    private void send(ChannelHandlerContext ctx, String context, HttpResponseStatus status) {
        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, Unpooled.copiedBuffer(context, CharsetUtil.UTF_8));
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }

    /*
     * 建立连接时,返回消息
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("连接的客户端地址:" + ctx.channel().remoteAddress());
        ctx.writeAndFlush("客户端" + InetAddress.getLocalHost().getHostName() + "成功与服务端建立连接! ");
        super.channelActive(ctx);
    }
}

至此,一个https服务器搭建好了(如何生成jks秘钥—>传送门)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章