使用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祕鑰—>傳送門)

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