HTTPS / TLS / HTTP2
ACE Framework 通过 ace-http 的 tlsFromPemFiles() 函数与 ListenOptions.tls 字段启用 HTTPS,底层基于 stdx.net.tls,支持 RSA / ECDSA / SM2 证书。启用 TLS 后默认同时启用 HTTP/2(经 ALPN 协商,不支持 h2 的客户端自动回落 HTTP/1.1)。
方式一:配置文件驱动(推荐)
在 application.toml 中配置证书路径,AceApplication.run() 自动启用 TLS:
# application.toml
[server]
host = "0.0.0.0"
port = 8443
[server.tls]
cert = "/etc/ssl/certs/server.crt" # 证书链 PEM(叶子在前,CA 在后)
key = "/etc/ssl/private/server.key" # 私钥 PEM
# keyPassword = "changeit" # 可选,加密私钥的口令
# http2 = false # 可选,关闭 HTTP/2(默认开启)应用代码无需任何改动:
main(): Int64 {
AceApplication.run() // 自动读取 server.tls.cert / server.tls.key
return 0
}服务启动后输出:
ACE serving on https://0.0.0.0:8443 (env=local)方式二:编程式配置
使用 tlsFromPemFiles() 构造 TLS 配置,通过 ListenOptions 传入:
import ace_http.*
main(): Int64 {
let app = AceApplication.buildApp()
var opts = ListenOptions()
opts.tls = tlsFromPemFiles("server.crt", "server.key")
listenWith(app, "0.0.0.0", 8443, opts)
return 0
}加密私钥(带口令):
opts.tls = tlsFromPemFiles("server.crt", "server.key", "p@ssw0rd")HTTP/2
配置 TLS 后 HTTP/2 即自动可用,无需额外代码:tlsFromPemFiles 默认把 ALPN 协商列表设为 ["h2", "http/1.1"],stdx 服务端按握手协商结果自动选择 HTTP/2 或 HTTP/1.1 引擎。所有能力(路由、中间件、SSE 流式、二进制响应、gzip 等)在两个协议下行为一致。
# 验证协商结果(自签名证书加 -k)
curl -k --http2 https://localhost:8443/api/ping -w '\nhttp_version=%{http_version}\n'
# => pong
# => http_version=2如需关闭(仅 HTTP/1.1):
[server.tls]
http2 = false编程式等价写法:
opts.tls = tlsFromPemFiles("server.crt", "server.key", http2: false)注意事项:
- HTTP/2 仅在 TLS 上可用(stdx 服务端不支持明文 h2c),明文端口恒为 HTTP/1.1——浏览器同样只支持 TLS 上的 h2,因此这不构成实际限制。
- 流式响应(SSE 等)在 HTTP/1.1 下走
Transfer-Encoding: chunked,HTTP/2 下由 DATA 帧天然分块(框架自动区分,h2 响应不携带 connection 级头)。 - WebSocket 两个协议都支持:HTTP/1.1 走
Upgrade: websocket握手(RFC 6455),HTTP/2 走 extended CONNECT(RFC 8441,服务端已下发SETTINGS_ENABLE_CONNECT_PROTOCOL),同一@WsController端点无差别服务两种客户端。
证书格式
证书链 PEM
若使用 CA 签发的证书,cert 文件须包含完整证书链(叶子证书在前,中间 CA 在后):
-----BEGIN CERTIFICATE-----
(你的域名证书)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(中间 CA 证书)
-----END CERTIFICATE-----支持的密钥类型
tlsFromPemFiles 使用 GeneralPrivateKey.decodeFromPem 自动识别密钥类型:
| 类型 | PEM 头部 |
|---|---|
| RSA | -----BEGIN RSA PRIVATE KEY----- 或 PKCS#8 |
| ECDSA | -----BEGIN EC PRIVATE KEY----- 或 PKCS#8 |
| SM2 | Cangjie stdx 支持的 SM2 格式 |
自签名证书(开发环境)
# 生成 ECDSA 自签名证书(有效期 365 天)
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 \
-keyout server.key -out server.crt \
-days 365 -nodes \
-subj "/CN=localhost"开发配置:
# application-local.toml
[server.tls]
cert = "server.crt"
key = "server.key"浏览器访问 https://localhost:8443 需手动信任自签名证书,或使用 curl -k。
连接超时与请求大小限制
通过 ListenOptions 同时配置 TLS、超时与请求大小上限:
var opts = ListenOptions()
opts.tls = tlsFromPemFiles("server.crt", "server.key")
opts.readTimeoutMs = 30000 // 30 秒读取超时
opts.writeTimeoutMs = 30000 // 30 秒写入超时
opts.maxRequestBodySize = Some(8_388_608) // 请求体上限 8MB,超出回 413(防大上传 OOM)
opts.maxRequestHeaderSize = Some(16_384) // 请求头上限 16KB,超出回 431(防恶意大头)
listenWith(app, "0.0.0.0", 8443, opts)大小上限不设置(None)时用 stdx 默认(body 2MB);Some(0) 表示显式无限。 配置驱动启动(Application.run())对应配置键 server.maxRequestBodySize / server.maxRequestHeaderSize。
HTTP + HTTPS 双端口
如需同时监听 HTTP(用于重定向)和 HTTPS,启动两个协程:
import ace_http.*
import ace_web.*
import std.sync.*
main(): Int64 {
let app = AceApplication.buildApp()
// HTTP 端口:强制重定向到 HTTPS
let redirectApp = App()
redirectApp.use({ctx: Context, _: Next =>
ctx.status = 301
ctx.setHeader("Location", "https://yourdomain.com${ctx.path}")
})
let latch = CountDownLatch(2)
spawn {
listen(redirectApp, "0.0.0.0", 8080)
latch.countDown()
}
spawn {
var opts = ListenOptions()
opts.tls = tlsFromPemFiles("server.crt", "server.key")
listenWith(app, "0.0.0.0", 8443, opts)
latch.countDown()
}
latch.await()
return 0
}反向代理(Let's Encrypt)
生产环境推荐在 Nginx / Caddy 等反向代理处终止 TLS,ACE 服务监听 HTTP:
# Nginx 配置
server {
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}此场景 ACE 无需配置 TLS,应用代码读取 X-Forwarded-Proto 头判断请求协议。
生产检查清单
- [ ] 证书链完整(叶子证书 + 中间 CA)
- [ ] 私钥权限
chmod 600 server.key - [ ] 证书有效期监控(建议提前 30 天告警)
- [ ] 仅启用 TLS 1.2+(stdx 默认已限制)
- [ ] 生产环境
keyPassword通过环境变量或密钥管理服务注入,勿写入配置文件