如何在Reactor Netty/Spring WebFlux中获取服务端SSL证书?
在Reactor Netty及Spring WebFlux中获取服务器证书的方案
一、Reactor Netty原生实现
Reactor Netty完全可以实现客户端读取服务器证书,核心是通过自定义SslContext配置,结合SslHandler的握手回调提取证书链:
- 构建自定义
SslContext,为SslHandler添加握手完成后的监听器 - 配置Reactor Netty的
HttpClient绑定该SslContext,发起请求触发握手
示例代码:
import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.SslHandler; import reactor.netty.http.client.HttpClient; import java.security.cert.Certificate; import javax.net.ssl.SSLSession; public class ReactorNettyCertReader { public void fetchServerCert(String url) throws Exception { // 构建客户端SslContext SslContext sslContext = SslContextBuilder.forClient().build(); HttpClient client = HttpClient.create() .secure(sslSpec -> sslSpec.sslContext(sslContext) .handlerConfigurator(sslHandler -> { // 监听握手完成事件,提取证书 sslHandler.handshakeFuture().addListener(future -> { if (future.isSuccess()) { SSLSession sslSession = sslHandler.engine().getSession(); try { Certificate[] certificates = sslSession.getPeerCertificates(); for (Certificate cert : certificates) { System.out.println("证书信息:" + cert); } } catch (Exception e) { e.printStackTrace(); } } }); })); // 发起请求触发握手(实际业务中建议用subscribe替代block) client.get() .uri(url) .response() .block(); } }
二、Spring WebFlux/WebClient方案
如果使用Spring WebFlux,可以通过自定义ClientHttpConnector配置Reactor Netty客户端,将证书获取逻辑集成到WebClient中:
示例代码:
import org.springframework.web.reactive.function.client.WebClient; import org.springframework.http.client.reactive.ReactorClientHttpConnector; import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.SslHandler; import reactor.netty.http.client.HttpClient; import java.security.cert.Certificate; import javax.net.ssl.SSLSession; @Configuration public class WebClientCertConfig { public WebClient webClientWithCertReader() throws Exception { SslContext sslContext = SslContextBuilder.forClient().build(); HttpClient httpClient = HttpClient.create() .secure(sslSpec -> sslSpec.sslContext(sslContext) .handlerConfigurator(sslHandler -> { sslHandler.handshakeFuture().addListener(future -> { if (future.isSuccess()) { SSLSession sslSession = sslHandler.engine().getSession(); try { Certificate[] certificates = sslSession.getPeerCertificates(); for (Certificate cert : certificates) { System.out.println("WebClient获取的证书:" + cert); } } catch (Exception e) { e.printStackTrace(); } } }); })); return WebClient.builder() .clientConnector(new ReactorClientHttpConnector(httpClient)) .build(); } } // 业务层使用示例 @Service public class CertService { private final WebClient webClient; public CertService(WebClient webClient) { this.webClient = webClient; } public void fetchCert(String url) { webClient.get() .uri(url) .retrieve() .bodyToMono(String.class) .subscribe(); } }
关键说明
- 底层都是通过
SSLSession.getPeerCertificates()获取证书链,和HttpsURLConnection.getServerCertificates()逻辑一致 - 响应式场景下优先使用
subscribe()或链式调用,避免用block()阻塞线程 - 如需对证书做校验、解析或持久化,可直接在握手回调中扩展业务逻辑
内容的提问来源于stack exchange,提问作者patsw
相关产品推荐
相关产品推荐

