Spray(12)spray-can - Http Client HttpDialog and Spray Client

Spray(12)spray-can - Http Client HttpDialog and Spray Client

3. HttpClient
HttpsExample
The difference between Http and Https for HttpDialog is that, what tags we bring to it.

val responseFuture =
     HttpDialog(httpClient, "github.com", port = 443, HttpClient.SslEnabled)
     .send(HttpRequest(uri = "/spray/spray"))
     .end

Google Query Example
Check all the configuration in spray-can/src/main/resources/reference.conf

What I need to for the spray-can is as follow:
spray.can {
  client {
     idle-timeout = 60 s
     request-timeout = 30 s
  }
  server {
request-timeout = 50s
}

}


We can do the requests in queue.

4. Http Dialog
package com.sillycat.easyspray.httpdialog

import java.util.concurrent.TimeUnit._
import scala.concurrent.Future
import scala.concurrent.duration.Duration
import spray.can.client.{ HttpDialog, HttpClient }
import spray.io._
import spray.http._
import HttpMethods._
import akka.actor.ActorSystem
import akka.actor.Props
import spray.httpx.RequestBuilding._

object SimpleExampleApp extends App {

  implicit valsystem = ActorSystem("simple-example")
  import system.log

  //different way to get the httpClient object
  val ioBridge = IOExtension(system).ioBridge()
  val client = system.actorOf(Props(new HttpClient(ioBridge)))

  //simple request
  val response: Future[HttpResponse] =
    HttpDialog(client, "www.google.com", 80)
      .send(HttpRequest(method = GET, uri = "/"))
      .end
  //multiple requests, fire one by one
  val responses1: Future[Seq[HttpResponse]] =
    HttpDialog(client, "www.google.com", 80)
      .send(Post("/shout", "yeah!"))
      .awaitResponse
      .send(Put("/count", "42"))
      .end

  //multiple requests, fire at same time
  val responses2: Future[Seq[HttpResponse]] =
    HttpDialog(client, "www.google.com", 80)
      .send(Get("/img/a.gif"))
      .send(Get("/img/b.gif"))
      .send(Get("/img/c.gif"))
      .end

  //multiple requests, fire follow this request -> response ->request
  val response3: Future[HttpResponse] =
    HttpDialog(client, "www.google.com", 80)
      .send(Get("/ping"))
      .reply(response => Get("/ping2", response.entity))
      .end

}

5. Spray Client
The default configuration file will be spray-client/src/main/resources/reference.conf

My first Simplest Example
package com.sillycat.easyspray.sprayclient

import spray.client._
import scala.concurrent.Future
import akka.actor._
import spray.can.client.HttpClient
import spray.client.HttpConduit
import spray.io._
import spray.util._
import spray.http._
import HttpMethods._
import scala.util.{Success, Failure}
import scala.concurrent.duration._
import akka.actor.{Props, ActorSystem}
import akka.pattern.ask
import akka.util.Timeout
import akka.event.Logging
import spray.json.{JsonFormat, DefaultJsonProtocol}
import spray.httpx.SprayJsonSupport
import spray.http._
import spray.util._

object SprayClientApp extends App  {

  implicit val system = ActorSystem()
  val ioBridge = IOExtension(system).ioBridge()
  val httpClient = system.actorOf(Props(new HttpClient(ioBridge)))

  val conduit = system.actorOf(
    props = Props(new HttpConduit(httpClient, "maps.googleapis.com", 80)),
    name = "http-conduit")
   
  val pipeline = HttpConduit.sendReceive(conduit)
 
  val response: Future[HttpResponse] = pipeline(HttpRequest(method = GET, uri = "/maps/api/elevation/json?locations=27.988056,86.925278&sensor=false"))

  response onComplete {
    case Success(responseContent) =>
      println("The elevation of Mt. Everest is: {} m" + responseContent)
      shutdown()

    case Failure(error) =>
      println("Couldn't get elevation")
      shutdown()
  }

  def shutdown(): Unit = {
    system.shutdown()
  }


}

Let's take a look at the the Example from official website
First of all, the json Marshall things.
package com.sillycat.easyspray.sprayclient.version11m7

import spray.json.{JsonFormat, DefaultJsonProtocol}


case class Elevation(location: Location, elevation: Double)
case class Location(lat: Double, lng: Double)
case class GoogleApiResult[T](status: String, results: List[T])

object ElevationJsonProtocol extends DefaultJsonProtocol {
  implicit val locationFormat = jsonFormat2(Location)
  implicit val elevationFormat = jsonFormat2(Elevation)
  implicit def googleApiResultFormat[T :JsonFormat] = jsonFormat2(GoogleApiResult.apply[T])

}

Here is the main part.
package com.sillycat.easyspray.sprayclient.version11m7

import scala.util.{Success, Failure}
import akka.actor.{Props, ActorSystem}
import spray.can.client.DefaultHttpClient
import spray.client.HttpConduit
import spray.httpx.SprayJsonSupport
import spray.http._
import spray.util._


object Main extends App {
  // we need an ActorSystem to host our application in
  implicit val system = ActorSystem("simple-spray-client")
  import system.log

  // create and start the default spray-can HttpClient
  val httpClient = DefaultHttpClient(system)

  startExample1()

  def startExample1() {
    log.info("Getting http://github.com ...")
    // an HttpConduit gives us access to an HTTP server,
    // it manages a pool of connections to _one_ host/port combination
    // Get a Conduit
    val conduit = system.actorOf(
      props = Props(new HttpConduit(httpClient, "github.com")),
      name = "http-conduit-1"
    )

    // send a simple request
    val pipeline = HttpConduit.sendReceive(conduit)
    val responseFuture = pipeline(HttpRequest(method = HttpMethods.GET, uri = "/"))
    responseFuture onComplete {
      case Success(response) =>
        log.info(
          """|Response for GET request to github.com:
             |status : {}
             |headers: {}
             |body   : {}""".stripMargin,
          response.status.value, response.headers.mkString("\n  ", "\n  ", ""), response.entity.asString
        )
        system.stop(conduit) // the conduit can be stopped when all operations on it have been completed
        startExample2()

      case Failure(error) =>
        log.error(error, "Couldn't get http://github.com")
        system.shutdown() // also stops all conduits (since they are actors)
    }
  }

  //Build the Second conduit
  def startExample2() {
    log.info("Requesting the elevation of Mt. Everest from Googles Elevation API...")
    val conduit = system.actorOf(
      props = Props(new HttpConduit(httpClient, "maps.googleapis.com")),
      name = "http-conduit-2"
    )

    import HttpConduit._
    import ElevationJsonProtocol._
    import SprayJsonSupport._


    //send the request and unmarshal
    val pipeline = sendReceive(conduit) ~> unmarshal[GoogleApiResult[Elevation]]

    val responseF = pipeline(Get("/maps/api/elevation/json?locations=27.988056,86.925278&sensor=false"))
    responseF onComplete {
      case Success(response) =>
        log.info("The elevation of Mt. Everest is: {} m", response.results.head.elevation)
        system.shutdown() // also stops all conduits (since they are actors)

      case Failure(error) =>
        log.error(error, "Couldn't get elevation")
        system.shutdown() // also stops all conduits (since they are actors)
    }
  }

}

Some other magic Not in the Example

case class Order(id: Int)
case class OrderConfirmation(id: Int)

object MyJsonProtocol extends DefaultJsonProtocol {
  implicit val orderFormat = jsonFormat1(Order)
  implicit val orderConfirmationFormat = jsonFormat1(OrderConfirmation)
}

import HttpConduit._
import MyJsonProtocol._

val pipeline: HttpRequest => Future[OrderConfirmation] = (
  addHeader("X-My-Special-Header", "fancy-value")
  ~> addCredentials(BasicHttpCredentials("bob", "secret"))
  ~> encode(Gzip)
  ~> sendReceive(conduit)
  ~> decode(Deflate)
  ~> unmarshal[OrderConfirmation]
)
val confirmation: Future[OrderConfirmation] =
  pipeline(Post("/orders", Order(42))

Till now, I got everything from the document. I plan to integrate that in the project.

Tips:

References:
spray(12)spray-can - Http Client
http://sillycat.iteye.com/blog/1882919

Http Dialog
http://spray.io/documentation/spray-can/http-dialog/

猜你喜欢

转载自sillycat.iteye.com/blog/1882963