HTTPS 配置
This content is not available in your language yet.
Feat 通过 SslPlugin 插件为 HTTP 服务提供 HTTPS 支持。你不需要重写业务代码,只需添加 SSL 插件即可将 HTTP 服务升级为 HTTPS。
基础 HTTPS 服务
Section titled “基础 HTTPS 服务”使用 PEM 格式证书创建 HTTPS 服务:
import io.github.smartboot.socket.extension.plugins.SslPlugin;import io.github.smartboot.socket.extension.ssl.factory.PemServerSSLContextFactory;import tech.smartboot.feat.Feat;
import java.io.InputStream;
public class HttpsDemo { public static void main(String[] args) throws Exception { // 加载证书文件 InputStream certPem = HttpsDemo.class.getClassLoader() .getResourceAsStream("example.org.pem"); InputStream keyPem = HttpsDemo.class.getClassLoader() .getResourceAsStream("example.org-key.pem");
// 创建 SSL 插件 SslPlugin sslPlugin = new SslPlugin( new PemServerSSLContextFactory(certPem, keyPem) );
// 启动 HTTPS 服务 Feat.httpServer(opt -> opt.addPlugin(sslPlugin)) .httpHandler(req -> req.getResponse().write("Hello HTTPS")) .listen(); }}本地开发推荐使用 mkcert 生成本地可信证书:
# 安装 mkcertbrew install mkcert # macOS# 或下载对应系统的二进制文件
# 生成证书mkcert example.com "*.example.com" localhost 127.0.0.1 ::1执行后会生成两个文件:
example.com+4.pem- 证书文件example.com+4-key.pem- 私钥文件
将这两个文件放入项目的 src/main/resources 目录。
SSL 插件配置
Section titled “SSL 插件配置”自动生成的证书
Section titled “自动生成的证书”测试环境可以使用 AutoServerSSLContextFactory 自动生成自签名证书:
import io.github.smartboot.socket.extension.ssl.factory.AutoServerSSLContextFactory;
SslPlugin sslPlugin = new SslPlugin(new AutoServerSSLContextFactory());
Feat.httpServer(opt -> opt.addPlugin(sslPlugin)) .httpHandler(req -> req.getResponse().write("Auto HTTPS")) .listen();支持为不同域名配置不同证书:
import io.github.smartboot.socket.extension.ssl.factory.PemServerSSLContextFactory;import java.util.HashMap;import java.util.Map;
// 配置多域名证书Map<String, PemServerSSLContextFactory> certMap = new HashMap<>();certMap.put("example.com", new PemServerSSLContextFactory( certPem1, keyPem1));certMap.put("api.example.com", new PemServerSSLContextFactory( certPem2, keyPem2));
SslPlugin sslPlugin = new SslPlugin( (socketAddress, engine) -> { // 根据域名返回对应证书 return certMap.get(engine.getPeerHost()); });处理 HTTPS 请求
Section titled “处理 HTTPS 请求”HTTPS 请求的处理方式与 HTTP 完全相同:
Feat.httpServer(opt -> opt.addPlugin(sslPlugin)) .httpHandler(req -> { // 获取请求信息 String method = req.getMethod(); String uri = req.getRequestURI();
// 设置响应 req.getResponse() .setContentType("application/json") .write("{\"status\":\"ok\"}"); }) .listen(8443);获取 SSL 信息
Section titled “获取 SSL 信息”通过 SSLEngine 获取 TLS 连接详情:
import javax.net.ssl.SSLEngine;import javax.net.ssl.SSLSession;
Feat.httpServer(opt -> opt.addPlugin(sslPlugin)) .httpHandler(req -> { SSLEngine engine = req.getSslEngine();
if (engine != null) { SSLSession session = engine.getSession();
// 获取协议版本 String protocol = session.getProtocol(); // TLSv1.3
// 获取加密套件 String cipher = session.getCipherSuite(); // TLS_AES_256_GCM_SHA384
req.getResponse().write("Protocol: " + protocol); } else { req.getResponse().write("Not HTTPS"); } }) .listen();启用 SSLEngine 访问
Section titled “启用 SSLEngine 访问”如需在业务代码中访问 SSLEngine,需要在插件初始化时进行设置:
import io.github.smartboot.socket.extension.ssl.factory.AutoServerSSLContextFactory;import tech.smartboot.feat.core.server.HttpRequest;
import javax.net.ssl.SSLEngine;import java.util.function.Consumer;
SslPlugin sslPlugin = new SslPlugin( new AutoServerSSLContextFactory(), (Consumer<SSLEngine>) sslEngine -> { // 将 SSLEngine 存入 ThreadLocal HttpRequest.SSL_ENGINE_THREAD_LOCAL.set(sslEngine); });
Feat.httpServer(opt -> opt.addPlugin(sslPlugin)) .httpHandler(req -> { SSLEngine engine = req.getSslEngine(); if (engine != null) { req.getResponse().write("Cipher: " + engine.getSession().getCipherSuite()); } }) .listen();客户端认证(mTLS)
Section titled “客户端认证(mTLS)”启用双向 TLS 认证,要求客户端提供证书:
import io.github.smartboot.socket.extension.ssl.ClientAuth;
SslPlugin sslPlugin = new SslPlugin( new PemServerSSLContextFactory(certPem, keyPem), ClientAuth.REQUIRE // 要求客户端证书);
Feat.httpServer(opt -> opt.addPlugin(sslPlugin)) .httpHandler(req -> { SSLEngine engine = req.getSslEngine(); if (engine != null) { // 获取客户端证书信息 javax.security.cert.X509Certificate[] certs = engine.getSession().getPeerCertificateChain(); req.getResponse().write("Client: " + certs[0].getSubjectDN()); } }) .listen();ClientAuth 模式:
| 模式 | 说明 |
|---|---|
NONE | 不验证客户端证书(默认) |
REQUEST | 请求客户端证书,但不强制 |
REQUIRE | 强制要求客户端证书 |
基础 HTTPS 服务
Section titled “基础 HTTPS 服务”import io.github.smartboot.socket.extension.plugins.SslPlugin;import io.github.smartboot.socket.extension.ssl.factory.PemServerSSLContextFactory;import tech.smartboot.feat.Feat;import tech.smartboot.feat.core.common.HeaderName;import tech.smartboot.feat.core.common.HttpStatus;
import java.io.InputStream;
public class HttpsBasicDemo { public static void main(String[] args) throws Exception { // 1. 加载证书 InputStream certPem = HttpsBasicDemo.class.getClassLoader() .getResourceAsStream("server.pem"); InputStream keyPem = HttpsBasicDemo.class.getClassLoader() .getResourceAsStream("server-key.pem");
if (certPem == null || keyPem == null) { System.err.println("证书文件未找到"); return; }
// 2. 创建 SSL 插件 SslPlugin sslPlugin = new SslPlugin( new PemServerSSLContextFactory(certPem, keyPem) );
// 3. 启动 HTTPS 服务 Feat.httpServer(opt -> { opt.addPlugin(sslPlugin); opt.port(8443); }) .httpHandler(req -> { // 获取协议信息 String protocol = req.getProtocol(); // HTTPS/1.1
req.getResponse() .setHeader(HeaderName.CONTENT_TYPE, "application/json") .write("{\"message\":\"Secure connection established\"}"); }) .listen();
System.out.println("HTTPS server started on https://localhost:8443"); }}带 SSL 信息输出的服务
Section titled “带 SSL 信息输出的服务”import io.github.smartboot.socket.extension.plugins.SslPlugin;import io.github.smartboot.socket.extension.ssl.factory.AutoServerSSLContextFactory;import tech.smartboot.feat.Feat;import tech.smartboot.feat.core.server.HttpRequest;
import javax.net.ssl.SSLEngine;import javax.net.ssl.SSLSession;import java.util.function.Consumer;
public class HttpsInfoDemo { public static void main(String[] args) throws Exception { // 创建带 SSLEngine 回调的 SSL 插件 SslPlugin sslPlugin = new SslPlugin( new AutoServerSSLContextFactory(), (Consumer<SSLEngine>) sslEngine -> { HttpRequest.SSL_ENGINE_THREAD_LOCAL.set(sslEngine); } );
Feat.httpServer(opt -> opt.addPlugin(sslPlugin)) .httpHandler(req -> { SSLEngine engine = req.getSslEngine(); StringBuilder info = new StringBuilder();
if (engine != null) { SSLSession session = engine.getSession(); info.append("Protocol: ").append(session.getProtocol()).append("\n"); info.append("Cipher Suite: ").append(session.getCipherSuite()).append("\n"); info.append("Peer Host: ").append(session.getPeerHost()).append("\n"); }
req.getResponse().write(info.toString()); }) .listen(); }}浏览器提示证书不受信任
Section titled “浏览器提示证书不受信任”原因:使用的是自签名证书。
解决:
- 本地开发使用
mkcert生成可信证书 - 生产环境使用正规 CA 签发的证书
- 测试环境可手动将证书添加到浏览器信任列表
证书文件加载失败
Section titled “证书文件加载失败”排查清单:
- 确认文件名与代码中一致
- 确认文件在
src/main/resources目录下 - 确认文件已打包进 jar(检查构建输出)
- 使用绝对路径测试:
InputStream cert = new FileInputStream("/absolute/path/to/cert.pem");
HTTPS 无法访问
Section titled “HTTPS 无法访问”检查项:
- 确认访问的是
https://而非http:// - 确认端口正确(默认 8080,除非显式指定)
- 确认防火墙允许该端口
- 检查控制台是否有 SSL 相关错误日志
SSLEngine 返回 null
Section titled “SSLEngine 返回 null”原因:默认情况下 SSLEngine 不会自动设置到请求对象。
解决:创建 SslPlugin 时添加回调:
SslPlugin sslPlugin = new SslPlugin( sslContextFactory, (Consumer<SSLEngine>) sslEngine -> { HttpRequest.SSL_ENGINE_THREAD_LOCAL.set(sslEngine); });HTTP/2 支持
Section titled “HTTP/2 支持”Feat 的 HTTPS 支持 HTTP/2 协议,无需额外配置。客户端使用 ALPN 协商协议版本:
// 服务端代码无需修改,自动支持 HTTP/2Feat.httpServer(opt -> opt.addPlugin(sslPlugin)) .httpHandler(req -> { // req.getProtocol() 返回 HTTP/2.0 或 HTTP/1.1 req.getResponse().write("Protocol: " + req.getProtocol()); }) .listen();