我正在从 Play 应用程序访问 SSL 安全页面。 当页面的证书不可信任时(因为它已过期或自签名或 不管是什么原因)我想从我的电话中提取这些信息并且 相应地做一些 Action 。 当我在浏览器中访问这样的页面时,它会警告我有问题 证书。 当我在游戏中写这样的东西时(这里的 https 页面有一个错误的证书):
package controllers
import play.api.mvc.{Action, Controller}
import play.api.libs.ws.WS
import java.util.concurrent.TimeUnit
object CallHttpsController extends Controller{
def callHttps() = Action {
val url = "https://xceed.no-ip.org/"
val response: play.api.libs.ws.Response = WS.url(url).get.await(3, TimeUnit.SECONDS).get
response.status match {
case OK => Ok("Got response: " + response.body)
case _ => Ok("Something went wrong: "+response.status+" "+response.body)
}
}
}
响应状态正常,我希望它会抛出异常,说明有问题 带证书。
是否有可能在游戏中调用这样的页面并在证书不可信时得到异常? 默认支持 Play 吗? 有没有人有类似的问题/需要?
提前致谢。
更新#1: 感谢 Ning 的提示。 我在构建脚本中添加了依赖项:
lazy val appDependencies = Seq(
"com.ning" % "async-http-client" % "1.7.5"
)
图书馆本身确实很有帮助。然而,要按预期使用 SSL,显然需要初始化 SSL 上下文。我尝试了以下代码:
def callHttps() = Action {
try{
val url = "https://xceed.no-ip.org/"
val response: play.api.libs.ws.Response = WS.url(url).get.await(3, TimeUnit.SECONDS).get // => No problem here
Console.println(WS.client.getConfig.getSSLContext) // => null
val sslContext = SSLContext.getDefault;
val playConfig = play.api.Play.maybeApplication.map(_.configuration)
val asyncHttpConfig = new AsyncHttpClientConfig.Builder()
.setConnectionTimeoutInMs(playConfig.flatMap(_.getMilliseconds("ws.timeout")).getOrElse(120000L).toInt)
.setRequestTimeoutInMs(playConfig.flatMap(_.getMilliseconds("ws.timeout")).getOrElse(120000L).toInt)
.setFollowRedirects(playConfig.flatMap(_.getBoolean("ws.followRedirects")).getOrElse(true))
.setUseProxyProperties(playConfig.flatMap(_.getBoolean("ws.useProxyProperties")).getOrElse(true))
.setSSLContext( sslContext )
playConfig.flatMap(_.getString("ws.useragent")).map { useragent =>
asyncHttpConfig.setUserAgent(useragent)
}
val innerClient = new AsyncHttpClient(asyncHttpConfig.build())
val resp = innerClient.prepareGet(url).execute().get() // => exception
Console.println("All OK")
Ok("Got response: " + resp.getResponseBody)
}
catch {
case e: Exception =>
var cause = e.getCause
while (cause != null) {
Console.println("Caused by: \n" + e.getLocalizedMessage + "\n" + e.getStackTraceString)
cause = cause.getCause
}
Ok("Got Exception: " + e.getLocalizedMessage + "\n" + e.getStackTraceString)
}
}
从 WS 源代码中提取了一个客户端初始化,并将默认的 SSL 上下文传递给客户端。然后调用按预期失败。 将尝试通过游戏筹集门票...... 干杯!
更新#2: 票证现已解决,将成为 play 2.0.4 的一部分 https://play.lighthouseapp.com/projects/82401/tickets/655-ws-call-wont-fail-upon-https-call-to-a-page-with-wrong-certificate
更新 #3: 现在默认设置默认 ssl 上下文。要在应用程序配置文件中关闭它,请设置 ws.acceptAnyCertificate=true
有关详细信息,请参阅 WS.scala 代码: https://github.com/playframework/Play20/blob/master/framework/src/play/src/main/scala/play/api/libs/ws/WS.scala
最佳答案
在其 play.api.libs.ws.WS
类中,Play!框架使用 Ning Async HTTP Client Library (版本 1.7.0),它又使用 Netty network application framework (3.5 版)。 Netty 负责 SSL 验证,但其结果由异步 HTTP 客户端库处理。
似乎 SSL 验证只在 a recent commit of the Async HTTP Client library 中得到了正确修复,仅包含在 1.7.5 版本中。您可以尝试将较新的版本强制添加到您的项目中(即覆盖 Play 引用的 1.7.0 版本!),并可能打开一个问题,以便可以将较新的库版本包含在下一个 Play 中!发布。
关于web-services - 从 Play 应用程序访问 SSL 安全网页,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11901816/