Scala调用Facebook头像HTTPS连接异常排查求助
问题根源
你遇到的org.jboss.netty.handler.ssl.NotSslRecordException本质是旧版本Netty的SSL处理逻辑与Facebook头像CDN的TLS协议要求不兼容。Dispatch 0.11.2依赖的是Netty 3.x系列,这个版本对TLS 1.3的支持非常有限(甚至完全不支持),而Facebook的头像CDN节点可能强制使用TLS 1.3或对SSL握手有严格的现代协议要求,导致握手过程中出现协议不匹配,最终抛出“非SSL/TLS记录”的错误。
其他HTTPS网站正常是因为它们大多兼容旧版TLS协议(比如TLS 1.2及以下),而Facebook的CDN已经淘汰了这些旧协议支持。
解决方案1:升级Dispatch版本(推荐)
最直接有效的方法是升级到支持现代TLS协议的Dispatch版本。Dispatch 0.13.x及以上版本依赖Netty 4.x,对TLS 1.3有良好支持,且兼容Scala 2.11。
修改build.sbt:
name := "url-test" organization := "dev.undrewb" version := "0.0.1" scalaVersion := "2.11.12" resolvers ++= Seq( "Sonatype releases" at "https://oss.sonatype.org/content/repositories/releases" ) libraryDependencies ++= { Seq( "net.databinder.dispatch" %% "dispatch-core" % "0.13.4" ) }
代码调整(几乎无需改动):
原有的fetchUrl函数可以直接使用,新版本的Dispatch API与旧版本兼容度很高:
import dispatch.Defaults._ import dispatch._ import scala.concurrent.Await import scala.concurrent.duration._ def fetchUrl(uri: String): Array[Byte] = { val svc = url(uri) val future_img = Http(svc OK as.Bytes) Await.result(future_img, 1.second) }
解决方案2:手动配置SSL上下文(不推荐,仅用于无法升级的场景)
如果因为项目限制无法升级Dispatch,你可以手动配置Netty的SSL上下文,强制使用兼容的TLS版本(比如TLS 1.2),并调整SSL参数:
自定义HttpClient配置:
import dispatch.Defaults._ import dispatch._ import scala.concurrent.Await import scala.concurrent.duration._ import javax.net.ssl.SSLContext import javax.net.ssl.TrustManagerFactory import java.security.KeyStore def createCustomHttpClient(): HttpClient = { // 初始化默认信任管理器 val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm) tmf.init(null.asInstanceOf[KeyStore]) val trustManagers = tmf.getTrustManagers // 创建支持TLS 1.2的SSL上下文 val sslContext = SSLContext.getInstance("TLSv1.2") sslContext.init(null, trustManagers, null) // 配置Dispatch的HttpClient使用自定义SSL上下文 val httpClient = new HttpClient { override def configureSSLContext = sslContext } httpClient } def fetchUrl(uri: String): Array[Byte] = { val svc = url(uri) val customHttp = createCustomHttpClient() val future_img = customHttp(svc OK as.Bytes) Await.result(future_img, 1.second) }
注意:这个方案可能无法完全解决问题,因为Facebook的CDN可能已经不再支持TLS 1.2,所以优先推荐升级Dispatch版本。
验证测试
升级或配置完成后,重新执行sbt console并调用fetchUrl传入Facebook头像的HTTPS URL,应该可以正常获取图片字节数组。
内容的提问来源于stack exchange,提问作者Andrew Bucknell

