Scala/Akka HTTP实现curl --cacert HTTPS请求报错问题咨询
问题根因
报错核心是Akka HTTP的SSL上下文类型传错:
你调用客户端发请求的singleRequest方法时,第二个参数要求传入客户端侧的HTTPS连接上下文,但你实际传入的是为服务端监听配置的服务端SSL上下文。Akka流的TLS层初始化时,识别到传入的是服务端上下文,会判定当前场景是绑定端口监听入站连接,不应该携带目标服务的host/port参数,和你发请求时传入的目标地址参数冲突,直接抛出Actor初始化异常。
另外你贴的代码还有两个会导致后续请求失败的隐藏问题:
- 你写的
HttpsServerContext里生成的自定义CA信任的SSLContext根本没有被传入请求方法,实际传的是名为getSslContextForNoCertificateCheck的上下文——从命名看这是跳过所有证书校验的配置,完全不符合你用指定CA做服务端校验的需求 - Authorization请求头格式错误,
Bearer和token内容之间缺少必填空格,就算SSL连接成功,也会因为鉴权头格式非法被服务端拒绝。
修复方案
按以下步骤调整即可:
- 基于自定义CA证书生成客户端专用的HTTPS连接上下文,注意用Akka提供的
httpsClient方法包装,不要生成服务端类型的上下文,参考实现:
import akka.http.scaladsl.{ConnectionContext, HttpsConnectionContext} import java.io.FileInputStream import java.security.cert.X509Certificate import java.security.{KeyStore, SecureRandom} import javax.net.ssl.{CertificateFactory, SSLContext, TrustManagerFactory} // 加载指定CA证书 val certInputStream = new FileInputStream("cacert.crt") val certFactory = CertificateFactory.getInstance("X.509") val customCaCert = certFactory.generateCertificate(certInputStream).asInstanceOf[X509Certificate] certInputStream.close() // 构造仅信任该CA的信任库 val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm) val trustKeyStore = KeyStore.getInstance(KeyStore.getDefaultType) trustKeyStore.load(null) trustKeyStore.setCertificateEntry("custom-trusted-ca", customCaCert) trustManagerFactory.init(trustKeyStore) // 初始化客户端SSL上下文,包装为Akka HTTP可识别的客户端连接上下文 val clientSslContext = SSLContext.getInstance("TLS") clientSslContext.init(null, trustManagerFactory.getTrustManagers, new SecureRandom()) val customHttpsContext: HttpsConnectionContext = ConnectionContext.httpsClient(clientSslContext)
- 修正请求逻辑的两处错误:
- 把
singleRequest的第二个参数替换为上面生成的customHttpsContext,移除原来传的跳过证书校验的上下文 - 修正Authorization头格式,在
Bearer后补空格
修正后的请求代码:
- 把
val request = HttpRequest(uri = targetUri) .withMethod(HttpMethods.GET) // 注意Bearer和token之间必须有空格 .withHeaders(RawHeader("Authorization", s"Bearer $tokenfileContents")) val responseFuture = Http().singleRequest(request, customHttpsContext)
- 运行前确认
cacert.crt的路径是程序运行时可访问的正确路径,避免文件找不到导致的信任库初始化失败。
内容的提问来源于stack exchange,提问作者Amos Guetta
相关产品推荐
相关产品推荐

