Netty的wss支持

1. 加载ssl证书的工具类

public class SslUtil {

    private static volatile SSLContext sslContext = null;

// type是PKCS12、path是pfx文件路径、password是pfx对应的密码
public static SSLContext createSSLContext(String type ,String path ,String password) throws Exception { if(null == sslContext){ synchronized (SslUtil.class) { if(null == sslContext){ // 支持JKS、PKCS12(我们项目中用的是阿里云免费申请的证书,下载tomcat解压后的pfx文件,对应PKCS12 KeyStore ks = KeyStore.getInstance(type); // 证书存放地址 InputStream ksInputStream = new FileInputStream(path); ks.load(ksInputStream, password.toCharArray()); KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(ks, password.toCharArray()); sslContext = SSLContext.getInstance("TLS"); sslContext.init(kmf.getKeyManagers(), null, null); } } } return sslContext; } }

2. 将SslHandler放在第一个

            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();

                            // SSL处理器
                            SSLContext sslContext = SslUtil.createSSLContext(BaseGlobal.getCertType(),
                                    BaseGlobal.getCertPath(), BaseGlobal.getCertPassword());
                            SSLEngine sslEngine = sslContext.createSSLEngine();
                            sslEngine.setNeedClientAuth(false);
                            sslEngine.setUseClientMode(false);
                            pipeline.addLast("sslHandler", new SslHandler(sslEngine));

                            pipeline.addLast("idleStateHandler", new IdleStateHandler(readerIdleTimeSeconds,
                                    writerIdleTimeSeconds, allIdleTimeSeconds));
                            ...
                        }
                    });

3. 因为我们项目的特殊性,还需要同时支持TCP、WS协议,所以使用多线程加载两个NettyServer

@EnableCaching
@EnableAutoConfiguration
@SpringBootApplication(scanBasePackages = "xxx")
@MapperScan(basePackages = "xxx")
@EnableAsync
public class V3xboxApplication {
    public static void main(String[] args) {
        SpringApplication.run(V3xboxApplication.class, args);

        // 启动服务端(客户端TCP连接)
        // 使用线程启动,是因为Netty的sync方法会阻塞线程
        // 此处不使用线程池的原因是这里只需要一个线程,不存在线程的频繁销毁创建
        NettyServerThread nettyServerThread = new NettyServerThread();
        Thread thread1 = new Thread(nettyServerThread);
        thread1.start();

        // 如果设置wss端口的话,则启动wss处理服务器
        if(StringUtil.isNotEmpty(BaseGlobal.getWssPort())) {
            NettyWssServerThread sslServerThread = new NettyWssServerThread();
            Thread thread2 = new Thread(sslServerThread);
            thread2.start();
        }
    }
}

4. 因为我们需要在程序动态判断WS还是WSS,所以在nginx的proxy配置了,这样后台就可以识别客户端是https还是http

proxy_set_header scheme  $scheme;

参考:https://www.cnblogs.com/qingyibusi/p/8572783.html

原文地址:https://www.cnblogs.com/roostinghawk/p/12649954.html