返回顶部

收藏

HTTP请求封装

更多

基于Qt Library的Http库,不过其实后来我发现,用Scala+Java原生的Http,是性能最好,而且也最容易控制的。这个代码权作去年项目的一个纪念吧。

Http.scala

package hk.com.yushin.helper

import com.trolltech.qt.gui._
import com.trolltech.qt.core._
import com.trolltech.qt.network._
import com.trolltech.qt.core.QByteArray
import scala.collection.mutable.{ HashMap, ArrayBuffer }
import com.agiers.util.{ JsValue, JsObject, JsNull }
import com.agiers.mvc.{ ActionParams, Base }
import hk.com.yushin.Sales

class Http(
  private var _host: String = Sales.config("server"),
  private var _port: Int = 80) extends com.agiers.mvc.Base {

  def host = _host
  def host_=(server: String) = _host = host

  def port = _port
  def port_=(port: Int) = _port = port

  lazy val handle: QHttp = new QHttp(host, port) {
    val proxy = Sales.config("proxy").split(":")
    if (proxy.length > 1 && proxy(0).length > 0 && proxy(1).length > 0) {
      try {
        this.setProxy(proxy(0), proxy(1).toInt)
      } catch {
        case _ =>
          log.error("Proxy设置有误,请检查配置文件!")
      }
    }
  }

  handle.done.connect(this, "__done(boolean)")
  private def __done(error: Boolean) {
    if (!error)
      if (status >= 200 && status < 300)
        this.fireEvent("complete")
      else
        this.fireEvent("failure")
    else
      this.fireEvent("error")
  }

//    handle.stateChanged.connect(StateChangeHandle(this), "apply(int)")
//    handle.dataReadProgress.connect(this, "test(int, int)")

  lazy val header: QHttpRequestHeader = new QHttpRequestHeader {
    this.setValue("Host", _host);
    this.setValue("Cookie", Session.value)
    this.setValue("ClientId", Sales.clientId)
  }

//    sealed case class EventHandle(val http: Http) {
//      def apply(state: Int) {
//        http.checkCookie
//        println(http.handle.state, state)
//        http.handle.state match {
//          case QHttp.State.Reading =>
//            if (status >= 200 && status < 300)
//              http.fireEvent("complete")
//            else if (status >= 500)
//              http.fireEvent("failure")
//          case _ =>
//        }
//      }
//    }

  // Event Start
  /**
   * 以下内容专属Http的事件接口
   */
  type Fn = Http => Unit
  type Ev = (String, Fn)

  private val events = HashMap[String, FnContainer]()

  sealed case class FnContainer(fn : Fn) {

    private var fns = ArrayBuffer[Fn](fn)

    def +(fn : Fn) : this.type = {
      fns += fn
      this
    }

    def fire(http: Http) : Http = {
      fns.foreach(_(http))
      http
    }
  }

  def hasEvent(s: String) : Boolean = events.contains(s.toEventName)

  def addEvent(s: String, fn : Fn) : this.type = {
    val name = s.toEventName
    if (!this.hasEvent(name))
      events(name) = FnContainer(fn)
    else
      events(name) + fn
    this
  }

  def fireEvent(s: String): this.type = {
    val name = s.toEventName
    if (this.hasEvent(name))
      events(name).fire(this)
    this
  }

  def addEvent(event : Ev) : this.type = this.addEvent(event._1, event._2)

  def addEvents(events : Ev*) : this.type = {
    events.foreach(this.addEvent(_))
    this
  }

  // Event Close

  private def seed = random(100000, 999999)
  private def date = currentTime(true)

  def beforeRequest() {
    header.setValue("Date", date.toString)
    header.setValue("Seed", seed.toString)
  }

  private def checkCookie {
    val res = handle.lastResponse
    if (res.hasKey("Set-Cookie")) {
      val str = res.value("Set-Cookie")
      Cookie.add(str)
      header.setValue("Cookie", Session.value)
    }
  }

  def get(path: String): this.type = {
    beforeRequest
    header.setRequest("GET", path)
    handle.request(header)
    this
  }

  def post(path: String, data: Map[String, String]): this.type = {
    beforeRequest
    val d = new QByteArray("")
    var index = 0
    data.foreach { kv =>
      index += 1
      d.append(kv._1.encodeSys).append("=").append(kv._2.encodeSys)
      if (index < data.size)
        d.append("&")
    }
    header.setValue("Post-Sign", d.toString.md5)
    header.setRequest("POST", path)
    header.setContentType("application/x-www-form-urlencoded");
    handle.request(header, d);
    this
  }

  private def generateDesKey(clientId: String, date: String, seed: String): String = {
    val clientIdLength = clientId.length
    val time = date.substring(0, 10)
    val ms = date.substring(10).toFloat / 1000
    val start = (ms * clientIdLength).toInt

    def trueStart(start: Int, i: Int, modify: Int): Int = {
      val pos = start + i + modify
      if (pos < clientIdLength)
        pos
      else
        pos - clientIdLength
    }

    var temp = new Array[String](seed.length)
    var index = 0
    seed.foreach { el =>
      val s = trueStart(start, index, el.toString.toInt)
      val str =
        if (s + 5 > clientIdLength) {
          clientId.substring(s) + clientId.substring(0, (5 - (clientIdLength - s)))
        } else {
          clientId.substring(s, s + 5)
        }
      temp(index) = str
      index += 1
    }

    var result = new StringBuilder
    var mix = new StringBuilder
    temp.foreach { part =>
      var pos = part.charAt(0).toByte % 4
      result.append(part.charAt(pos + 1))
      mix.append(part.substring(pos))
    }
    result.mkString + mix.mkString
  }

  def desPost(path: String, data: Map[String, String]): this.type = {
    beforeRequest
    val key = generateDesKey(header.value("ClientId"), header.value("Date"), header.value("Seed"))
    val d = new QByteArray("")
    var index = 0
    data.foreach { kv =>
      index += 1
      d.append(kv._1.encodeSys).append("=").append(kv._2.desEncryptBase64(key).encodeSys)
      if (index < data.size)
        d.append("&")
    }
    header.setValue("Post-Sign", d.toString.md5)
    header.setRequest("POST", path)
    header.setContentType("application/x-www-form-urlencoded");
    handle.request(header, d);
    this
  }

  def desDecrypt(value: String): String = {
    value.desDecryptBase64(generateDesKey(header.value("ClientId"), header.value("Date"), header.value("Seed")))
  }

  def status = handle.lastResponse.statusCode
  def response: String = handle.readAll.toString

//    def response = handle.readAll.toString
//    def status = handle.lastResponse.statusCode
}

object Http {

  def get(path: String): Http = new Http().get(path)
  def post(path: String, data: Map[String, String]): Http = new Http().post(path, data)
  def post(path: String, data: HashMap[String, String]): Http = new Http().post(path, data.toMap)
  def post(path: String, params: ActionParams): Http = new Http().post(path, params.data.toMap)

  def desPost(path: String, data: Map[String, String]): Http = new Http().desPost(path, data)
  def desPost(path: String, data: HashMap[String, String]): Http = new Http().desPost(path, data.toMap)
  def desPost(path: String, params: ActionParams): Http = new Http().desPost(path, params.data.toMap)
}

标签:HTTP,Scala

收藏

0人收藏

支持

0

反对

0

发表评论