Scala HTTP 通信
[履歴] [最終更新] (2016/06/03 22:08:14)
最近の投稿
注目の記事

ビルドツールの設定

Dispatch を利用します。

pom.xml (maven)

<dependency>
  <groupId>net.databinder.dispatch</groupId>
  <artifactId>dispatch-core</artifactId>
  <version>0.11.2</version>
</dependency>
<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
  <version>1.1.3</version>
</dependency>

build.sbt (sbt)

libraryDependencies ++= Seq(
  "net.databinder.dispatch" %% "dispatch-core" % "0.11.2",
  "ch.qos.logback" % "logback-classic" % "1.1.3"
)

とても簡単な例

同期しながら通信

import dispatch._, Defaults._

// 以下の二つと等価です:
// import dispatch._
// import dispatch.Defaults._

import java.lang.Thread

object Main {
  def main(args: Array[String]): Unit = {

    val svc = url("http://www.example.com")
    val future = Http(svc OK as.String)

    val f = future() // 同期

    println(f) //=> HTML 文字列
    println(f.length) //=> 1270
  }
}

非同期通信

import dispatch._, Defaults._
import java.lang.Thread

object Main {
  def main(args: Array[String]): Unit = {

    val svc = url("http://www.example.com")
    val future = Http(svc OK as.String)

    // レスポンスが得られてから実行されます。以下同様。
    for(f <- future)
      println(f)

    // Future[String] を Future[Int] に変換
    val futureLength = for(f <- future) yield f.length

    //
    // 完了しているかどうかで挙動が変化するメソッド
    //

    println(future.print) //=> Future(-incomplete-)
    println(futureLength.completeOption.getOrElse(-1)) //=> -1

    Thread.sleep(2000)

    println(future.print) //=> HTML 文字列
    println(futureLength.completeOption.getOrElse(-1)) //=> 1270
  }
}

様々な HTTP リクエストを構築

import dispatch._, Defaults._
import java.lang.Thread

object Main {
  def main(args: Array[String]): Unit = {

    // HTTP GET
    var req = url("http://www.example.com")

    // HTTPS GET
    var myHost = host("www.example.com")
    req = myHost.secure / "index.html"

    // HTTP ポート指定 GET
    myHost = host("www.example.com", 80)
    req = myHost / "index.html"

    // クエリパラメータの指定
    req = req.addQueryParameter("key", "value") // 記法1
    req = req <<? Map("key" -> "value") // 記法2

    // HTTP メソッド指定 (GET/POST/HEAD/PUT/PATCH/DELETE など)
    req = req.POST

    // Body 値の指定
    req = req.addParameter("key", "value") // 記法1
    req = req << Map("key" -> "value") // 記法2

    // 任意の文字列で Body 値を指定
    req = req.setContentType("application/json", "UTF-8")
    req = req << """{"key":"value"}"""

    // ファイル指定 (java.io.File) https://www.qoosky.io/techs/22c6cdc250
    // req = req.PUT
    // req = req <<< myFile

    val future = Http(req OK as.String)
    val f = future()
    println(f)
  }
}

複数の非同期通信

有限個

import dispatch._, Defaults._
import java.lang.Thread

object Main {
  def main(args: Array[String]): Unit = {

    val svc = url("http://www.example.com")
    val svc2 = url("http://www.example.com")

    val future = Http(svc OK as.String)
    val future2 = Http(svc2 OK as.String)

    val futureLength = for(f <- future) yield f.length
    val futureLength2 = for(f <- future2) yield f.length

    for {
      fl <- futureLength
      fl2 <- futureLength2
    } {
      println(fl == fl2) //=> true
    }

    def func(futureLength: Future[Int], futureLength2: Future[Int]) : Future[Boolean] = {
      for {
        fl <- futureLength
        fl2 <- futureLength2
      } yield fl == fl2
    }

    for(res <- func(futureLength, futureLength2))
      println(res) //=> true

    Thread.sleep(2000)
  }
}

無限個

import dispatch._, Defaults._
import java.lang.Thread

object Main {
  def main(args: Array[String]): Unit = {

    val svcList = List[String](
      "http://www.example.com/",
      "http://www.yahoo.co.jp/",
      "http://www.hatena.ne.jp"
    ).map(url(_))

    val futureList = for(svc <- svcList) yield Http(svc OK as.String) // map と同等の機能
    val futureLengthList =
      for(future <- futureList) yield // map と同等の機能
        for(f <- future) yield f.length // Future[String] から Future[Int] への変換

    val longest =
      for(lengthList <- Future.sequence(futureLengthList)) yield // List[Future[Int]] から Future[Int] への変換
        lengthList.max // List の機能

    for(l <- longest)
      println(l) //=> 96157

    Thread.sleep(2000)
  }
}

例外処理

Option 型を用いた例外処理

.option を利用すると Option 型の Future が取得できます。

import dispatch._, Defaults._

object Main {
  def main(args: Array[String]): Unit = {

    val svc = url("http://www.example.com") // 存在するホスト
    // val svc = url("http://dummy.example.com") // 存在しないホスト

    val future = Http(svc OK as.String).option // Future[Option[String]]

    val f = future()

    val html = f match {
      case Some(html) => html // www.example.com
      case None => null // dummy.example.com
    }
    println(html)
  }
}

onComplete を用いた例外処理

import dispatch._, Defaults._
import scala.util.{Success, Failure}

import java.lang.Thread

object Main {
  def main(args: Array[String]): Unit = {

    val svc = url("http://www.example.com") // 存在するホスト
    // val svc = url("http://dummy.example.com") // 存在しないホスト

    val future = Http(svc OK as.String)

    future.onComplete {
      case Success(html) => { // www.example.com
        println(html)
      }
      case Failure(e) => { // dummy.example.com
        println("エラーが発生しました: " + e.getMessage)
      }
    }

    Thread.sleep(2000)
  }
}
関連ページ
    概要 こちらのページで環境を構築した Spring Boot について、非同期処理の基本的な実装方法をまとめます。 関連する公式ドキュメント Creating Asynchronous Methods Scheduling Tasks Consuming a RESTful Web Service Task Execution and Scheduling
    概要 Akka 2.4.2 を用いたサンプルコード集です。動作には Java 8 以降が必要です。 Akka requires that you have Java 8 or later installed on your machine. インストール方法は複数提供されています。その一部を記載します。