Netty服务端集成SniHandler获取协商TLS版本及空值问题咨询
问题解答
一、为什么获取SniHandler返回null
SniHandler的核心工作逻辑决定了它完成SNI解析后会自动从pipeline中移除:当接收到携带SNI扩展的ClientHello报文后,SniHandler会根据你配置的domainNameMapping匹配到对应SslContext,构造SslHandler并替换掉自身在pipeline中的位置,随后SniHandler实例就被移除了。后续你在其他Handler中调用ctx.pipeline().get("sniHandler")时,该Handler已不存在,自然返回null。
二、如何获取协商得到的TLS版本
TLS协商版本存储在SslHandler持有的SSLSession中,不需要通过SniHandler获取,推荐通过监听握手完成事件的方式获取,实现更简单稳定:
实现步骤
- 确保你自定义的业务Handler添加在SniHandler之后,pipeline初始化示例:
p.addLast("sniHandler", new SniHandler(options.domainNameMapping)); p.addLast("yourBusinessHandler", new YourCustomHandler());
- 在自定义Handler中重写
userEventTriggered方法,监听SslHandshakeCompletionEvent事件,事件触发时即可读取协商版本:
@Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { if (evt instanceof SslHandshakeCompletionEvent) { SslHandshakeCompletionEvent handshakeEvent = (SslHandshakeCompletionEvent) evt; if (handshakeEvent.isSuccess()) { // 从pipeline获取替换SniHandler后生成的SslHandler SslHandler sslHandler = ctx.pipeline().get(SslHandler.class); SSLSession sslSession = sslHandler.engine().getSession(); // 得到协商后的TLS版本,返回值格式如TLSv1.2、TLSv1.3 String negotiatedTlsVersion = sslSession.getProtocol(); // 此处可将TLS版本存入Channel Attribute或业务日志中 } else { // 可添加TLS握手失败的异常处理逻辑 } } super.userEventTriggered(ctx, evt); }
额外提示
如果需要同时保留SNI匹配的域名信息,可以自定义继承SniHandler的类,重写lookup方法,将匹配到的域名存入ChannelAttribute中,后续业务Handler直接从Channel中读取即可,不需要尝试获取已被移除的SniHandler实例。
内容的提问来源于stack exchange,提问作者Harry
相关产品推荐
相关产品推荐

