// Compile in sbt
// Run in sbt>run get https://raw.githubusercontent.com/nraychaudhuri/scalainaction/master/
chap02/breakable.scala
//
// The command line in sbt is
// >run (post | get | delete | options) -d <request parameters comma separated -h
<headers comma separated> <url>
// at minimum you should specify action(post, get, delete, options) and url
import java.security.cert.X509Certificate
import javax.net.ssl._
import org.apache.http.client.entity.UrlEncodedFormEntity
import org.apache.http.client.methods._
import org.apache.http.conn.scheme.Scheme
import org.apache.http.conn.ssl.{SSLSocketFactory, X509HostnameVerifier}
import org.apache.http.impl.client._
import org.apache.http.message._
object RestClient extends App {
/*解析参数*/
def parseArgs(args: Array[String]): Map[String, List[String]] = {
def nameValuePair(paramName: String) = {
def values(commaSeperatedValues: String) = commaSeperatedValues.split(",").toList
val index = args.indexWhere(_ == paramName)
(paramName, if (index == -1) Nil else values(args(index + 1)))
}
Map(nameValuePair("-d"), nameValuePair("-h"))
}
def splitByEqual(nameValue: String): Array[String] = nameValue.split('=')
def headers = for (nameValue <- params("-h")) yield {
def tokens = splitByEqual(nameValue)
new BasicHeader(tokens(0), tokens(1))
}
def formEntity = {
def toJavaList(scalaList: List[BasicNameValuePair]) = {
java.util.Arrays.asList(scalaList.toArray: _*)
}
def formParams = for (nameValue <- params("-d")) yield {
def tokens = splitByEqual(nameValue)
new BasicNameValuePair(tokens(0), tokens(1))
}
def formEntity = new UrlEncodedFormEntity(toJavaList(formParams), "UTF-8")
formEntity
}
def handlePostRequest() = {
val httppost = new HttpPost(url)
headers.foreach {
httppost.addHeader(_)
}
httppost.setEntity(formEntity)
val responseBody = httpClient.execute(httppost, new BasicResponseHandler())
println(responseBody)
}
def handleGetRequest() = {
val query = params("-d").mkString("&")
val httpget = new HttpGet(s"$url?$query")
headers.foreach {
httpget.addHeader(_)
}
val responseBody = httpClient.execute(httpget, new BasicResponseHandler())
println(responseBody)
}
def handleDeleteRequest() = {
val httpDelete = new HttpDelete(url)
val httpResponse = httpClient.execute(httpDelete)
println(httpResponse.getStatusLine)
}
def handleOptionsRequest() = {
val httpOptions = new HttpOptions(url)
headers.foreach {
httpOptions.addHeader(_)
}
val httpResponse = httpClient.execute(httpOptions)
println(httpOptions.getAllowedMethods(httpResponse))
}
/*require 函数用于抛出异常*/
require(args.size >= 2, "at minimum you should specify action(post, get, " +
"delete, options) and url")
val command = args.head
val params = parseArgs(args)
val url = args.last
/** SNI(Server Name Indication) 问题
* 针对https服务器会使用SNI选择证书进行发送,但是本例不支持SNI(如一些Android系统),
* 在SSL/TLS握手期间,服务器无法根据客户端选择,哪种SNI证书发送,因此需要让其验证时为True
*/
val xtm = new X509TrustManager {
override def getAcceptedIssuers: Array[X509Certificate] = null
override def checkClientTrusted(p1: Array[X509Certificate], p2: String): Unit = {}
override def checkServerTrusted(p1: Array[X509Certificate], p2: String): Unit = {}
}
val hostnameVerifier = new X509HostnameVerifier {
override def verify(p1: String, p2: SSLSocket): Unit = {}
override def verify(p1: String, p2: X509Certificate): Unit = {}
override def verify(p1: String, p2: Array[String], p3: Array[String]): Unit = {}
override def verify(p1: String, p2: SSLSession): Boolean = true
}
//TLS1.0与SSL3.0基本上没有太大的差别,可粗略理解为TLS是SSL的继承者,但它们使用的是相同的SSLContext
val ctx = SSLContext.getInstance("TLS")
//使用TrustManager来初始化该上下文,TrustManager只是被SSL的Socket所使用
ctx.init(null, Array(xtm), null)
//创建SSLSocketFactory
var socketFactory = new SSLSocketFactory(ctx)
socketFactory.setHostnameVerifier(hostnameVerifier)
val httpClient = new DefaultHttpClient()
httpClient.getConnectionManager.getSchemeRegistry
.register(new Scheme("https", socketFactory, 443))
command match {
case "post" => handlePostRequest()
case "get" => handleGetRequest()
case "delete" => handleDeleteRequest()
case "options" => handleOptionsRequest()
}
}
OK,在控制台指定参数
post https://raw.githubusercontent.com/nraychaudhuri/scalainaction/master/chap02/breakable.scala