search
LoginSignup
9

More than 3 years have passed since last update.

posted at

updated at

Ktor HttpClientでGET

入門Kotlin coroutinesで coroutine を使った並行処理を勉強させていただきました。その後 Ktor に HTTPクライアントがあることを知り、これを使うと HTTP通信を非同期I/O化できるのではないかと思いました。そこで Ktor の Client のページを開くと「under construction」でしたので、ソースを見ながら動かしてみました。


HttpClient クラスのコンストラクターには HttpClientEngineFactory インターフェースの実装クラスを渡す必要があります。
HttpClientEngineFactory インターフェースの実装クラスは次の3つが用意されていました。

  • io.ktor.client.engine.cio.CIO
  • io.ktor.client.engine.apache.Apache
  • io.ktor.client.engine.jetty.Jetty

CIO は HTTP 接続できましたが、HTTPS で接続する場合は Apache を使う必要がありました。
(CIO は HTTP だけ対応、Apache は HTTP と HTTPS に対応しているようです。)
Jetty は HTTP2 接続できるようですが、まだ動かせていません。。

CIO で GET

build.gradle

group 'HttpClientCIO'
version '1.0-SNAPSHOT'

buildscript {
    ext {
        kotlin_version = '1.2.21'
        ktor_version = '0.9.1'
    }

    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

apply plugin: 'kotlin'
apply plugin: 'application'

sourceCompatibility = 1.8

mainClassName = 'HttpClientCIOKt'

repositories {
    mavenCentral()
    maven { url  "http://dl.bintray.com/kotlin/ktor" }
    maven { url "https://dl.bintray.com/kotlin/kotlinx" }
}

dependencies {
    // Kotlin
    compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"

    // Ktor
    compile "io.ktor:ktor-client-cio:$ktor_version"

    // Log
    compile "ch.qos.logback:logback-classic:1.2.1"

    // Testing
    testCompile group: 'junit', name: 'junit', version: '4.12'
}

compileKotlin {
    kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
    kotlinOptions.jvmTarget = "1.8"
}

kotlin {
    experimental {
        coroutines "enable"
    }
}

HttpClientCIO.kt

import io.ktor.client.HttpClient
import io.ktor.client.engine.cio.CIO
import io.ktor.client.request.*
import kotlinx.coroutines.experimental.*

fun main( args: Array<String> ) {
    val client = HttpClient( CIO )

    val response = runBlocking {
        client.get<String>( host = "www.example.com" )
    }

    println( response )

    client.close()
}

client.get<String>( host = "www.example.com" )
このように get メソッドに <String> を指定しているので、HTTPサーバーから受信した文字列が返ります。
受信した HTTP ヘッダーなどを参照したい場合は、下で説明しているように別の型を指定すると取得することができます。

Apache で GET

build.gradle

group 'HttpClientApache'
version '1.0-SNAPSHOT'

buildscript {
    ext {
        kotlin_version = '1.2.21'
        ktor_version = '0.9.1'
    }

    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

apply plugin: 'kotlin'
apply plugin: 'application'

sourceCompatibility = 1.8

mainClassName = 'HttpClientApacheKt'

repositories {
    mavenCentral()
    maven { url  "http://dl.bintray.com/kotlin/ktor" }
    maven { url "https://dl.bintray.com/kotlin/kotlinx" }
}

dependencies {
    // Kotlin
    compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"

    // Ktor
    compile "io.ktor:ktor-client-apache:$ktor_version"

    // Log
    compile "ch.qos.logback:logback-classic:1.2.1"

    // Testing
    testCompile group: 'junit', name: 'junit', version: '4.12'
}

compileKotlin {
    kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
    kotlinOptions.jvmTarget = "1.8"
}

kotlin {
    experimental {
        coroutines "enable"
    }
}

dependencies の ktor-client-cio が ktor-client-apache になっている以外はほぼ同じです。

import io.ktor.client.HttpClient
import io.ktor.client.engine.apache.Apache
import io.ktor.client.request.*
import kotlinx.coroutines.experimental.*

fun main( args: Array<String> ) {
    val client = HttpClient( Apache )

    val response = runBlocking {
        client.get<String>( scheme = "https", host = "www.example.com", port = 443 )
    }

    println( response )

    client.close()
}

こちらも HttpClient のコンストラクタに渡すクラスが CIO から Apache になっている以外はほぼ同じですが、scheme に https を指定しています。
CIO は HTTPS に対応していないようで、CIO を使っている時に https を指定すると実行時エラーが発生します。

接続パラメーター

HttpClient.get() に指定可能なパラメータは、io/ktor/client/request/builders.kt で確認することができます。
具体的には次のようになっています。

名前 デフォルト値
scheme String "http"
host String "localhost"
port Int 80
path String "/"
body Any EmptyContent
block HttpRequestBuilder.() -> Unit {}

port のデフォルトが 80 なので、scheme に https を指定した場合、port には 443 を指定する必要があります。(scheme に https を指定しても自動的に port 443 にはなりません。)

EmptyContent は OutgoingContent.NoContent と定義されていて、body が NoContent の場合 HTTPボディは送信されないようになっていました。
body は POST でデータを渡す時に使うと思うので POST で使ってみようと思います。
HTTPヘッダーを指定する場合は block を使います。

HTTPスターテス、HTTPヘッダーを参照

import io.ktor.client.HttpClient
import io.ktor.client.engine.cio.CIO
import io.ktor.client.request.*
import io.ktor.client.response.*
import kotlinx.coroutines.experimental.*


fun main( args: Array<String> ) {
    val client = HttpClient( CIO )

    val response = runBlocking {
        val res = client.get<HttpResponse>( host = "www.example.com" )
        println( res.version )    // "HTTP/1.1"(HTTP バージョン)
        println( res.status )     // "301 Moved Permanently"(HTTP ステータス)
        // HTTPヘッダー
        res.headers.forEach{ k, v ->
            println( "$k: $v" )
        }
        println()       // 改行
        res.readText()  // HTTPボディ
    }

    println( response )

    client.close()
}

これまでは get メソッドに <String> を指定してしていたのに対して、<HttpResponse> を指定すると、HTTP ステータスや HTTP ヘッダーを参照することができます。
HttpResponse のプロパティには次のようなものがあります。

名前 実体(確認中)
status HttpStatusCode data class HttpStatusCode(val value: Int, val description: String)
version HttpProtocolVersion data class HttpProtocolVersion(val name: String, val major: Int, val minor: Int)
requestTime Date java.util.Date
responseTime Date java.util.Date
headers HeadersBuilder Map<String, List<String>>

次は POST を使ってみたいと思います。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
9