Skip to content

リクエストの送信

クライアントの設定後、HTTPリクエストの送信を開始できます。これを行う主な方法は、URLをパラメーターとして受け取る.request()関数を使用することです。この関数内で、さまざまなリクエストパラメーターを設定できます。

  • GETPOSTPUTDELETEHEADOPTIONSPATCHなどのHTTPメソッドを指定します。
  • URLを文字列として設定するか、そのコンポーネント(ドメイン、パス、クエリパラメーターなど)を個別に設定します。
  • Unixドメインソケットを使用します。
  • ヘッダーとCookieを追加します。
  • リクエストボディ(例:プレーンテキスト、データオブジェクト、フォームパラメーター)を含めます。

これらのパラメーターはHttpRequestBuilderクラスによって公開されます。

kotlin
import io.ktor.client.request.*
import io.ktor.client.statement.*

val response: HttpResponse = client.request("https://ktor.io/") {
  // Configure request parameters exposed by HttpRequestBuilder
}

.request()関数は、HttpResponseオブジェクトとしてレスポンスを返します。HttpResponseは、文字列、JSONオブジェクトなどのさまざまな形式でレスポンスボディを取得するために必要なAPI、およびステータスコード、コンテンツタイプ、ヘッダーなどのレスポンスパラメーターを取得するためのAPIを公開しています。詳細については、レスポンスの受信を参照してください。

.request()は停止関数(suspending function)であり、コルーチンまたは別の停止関数内から呼び出す必要があります。停止関数の詳細については、コルーチンの基本を参照してください。

HTTPメソッドの指定

.request()関数を呼び出す際に、methodプロパティを使用して目的のHTTPメソッドを指定できます。

kotlin
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*

val response: HttpResponse = client.request("https://ktor.io/") {
    method = HttpMethod.Get
}

.request()に加えて、HttpClientは、.get().post().put()などの基本的なHTTPメソッドに特化した関数を提供します。上記の例は、.get()関数を使用すると簡略化できます。

kotlin
val response: HttpResponse = client.get("https://ktor.io/docs/welcome.html")

どちらの例でも、リクエストURLは文字列として指定されています。HttpRequestBuilderを使用してURLコンポーネントを個別に設定することもできます。

リクエストURLの指定

Ktorクライアントでは、さまざまな方法でリクエストURLを設定できます。

URL文字列全体を渡す

kotlin
val response: HttpResponse = client.get("https://ktor.io/docs/welcome.html")

URLコンポーネントを個別に設定する

kotlin
client.get {
    url {
        protocol = URLProtocol.HTTPS
        host = "ktor.io"
        path("docs/welcome.html")
    }
}

この場合、HttpRequestBuilderによって提供されるurlパラメーターが使用されます。これはURLBuilderのインスタンスを受け入れ、複雑なURLを構築するためのより多くの柔軟性を提供します。

すべてのリクエストのベースURLを設定するには、DefaultRequestプラグインを使用します。

パスセグメント

前の例では、URLBuilder.pathプロパティを使用してURLパス全体が指定されました。または、appendPathSegments()関数を使用して個々のパスセグメントを渡すこともできます。

kotlin
client.get("https://ktor.io") {
    url {
        appendPathSegments("docs", "welcome.html")
    }
}

デフォルトでは、appendPathSegmentsはパスセグメントをエンコードします。エンコーディングを無効にするには、代わりにappendEncodedPathSegments()を使用します。

クエリパラメーター

クエリ文字列パラメーターを追加するには、URLBuilder.parametersプロパティを使用します。
kotlin
client.get("https://ktor.io") {
    url {
        parameters.append("token", "abc123")
    }
}

デフォルトでは、parametersはクエリパラメーターをエンコードします。エンコーディングを無効にするには、代わりにencodedParameters()を使用します。

trailingQueryプロパティは、クエリパラメーターがない場合でも?文字を保持するために使用できます。

URLフラグメント

ハッシュマーク#は、URLの末尾近くにオプションのフラグメントを導入します。fragmentプロパティを使用してURLフラグメントを設定できます。

kotlin
client.get("https://ktor.io") {
    url {
        fragment = "some_anchor"
    }
}

デフォルトでは、fragmentはURLフラグメントをエンコードします。エンコーディングを無効にするには、代わりにencodedFragment()を使用します。

Unixドメインソケットの指定

Unixドメインソケットは、CIOエンジンでのみサポートされています。 KtorサーバーでUnixソケットを使用するには、それに応じてサーバーを設定します。

Unixドメインソケットをリッスンしているサーバーにリクエストを送信するには、CIOクライアントを使用する際にunixSocket()関数を呼び出します。

kotlin
val client = HttpClient(CIO)

val response: HttpResponse = client.get("/") {
    unixSocket("/tmp/test-unix-socket-ktor.sock")
}

デフォルトのリクエストの一部としてUnixドメインソケットを設定することもできます。

リクエストパラメーターの設定

HTTPメソッド、ヘッダー、Cookieなど、さまざまなリクエストパラメーターを指定できます。特定のクライアントのすべてのリクエストに対してデフォルトのパラメーターを設定する必要がある場合は、DefaultRequestプラグインを使用します。

ヘッダー

リクエストにヘッダーを追加する方法はいくつかあります。

複数のヘッダーを追加する

headers関数を使用すると、一度に複数のヘッダーを追加できます。

kotlin
client.get("https://ktor.io") {
    headers {
        append(HttpHeaders.Accept, "text/html")
        append(HttpHeaders.Authorization, "abc123")
        append(HttpHeaders.UserAgent, "ktor client")
    }
}

単一のヘッダーを追加する

header関数を使用すると、単一のヘッダーを追加できます。

認証にbasicAuthまたはbearerAuthを使用する

basicAuthおよびbearerAuth関数は、対応するHTTPスキームを持つAuthorizationヘッダーを追加します。

高度な認証設定については、Ktorクライアントでの認証と認可を参照してください。

Cookie

Cookieを送信するには、cookie()関数を使用します。

kotlin
client.get("https://ktor.io") {
    cookie(name = "user_name", value = "jetbrains", expires = GMTDate(
        seconds = 0,
        minutes = 0,
        hours = 10,
        dayOfMonth = 1,
        month = Month.APRIL,
        year = 2023
    ))
}

Ktorには、呼び出し間でCookieを保持できるHttpCookiesプラグインも用意されています。このプラグインがインストールされている場合、cookie()関数を使用して追加されたCookieは無視されます。

リクエストボディの設定

リクエストボディを設定するには、HttpRequestBuilderによって提供されるsetBody()関数を呼び出します。この関数は、プレーンテキスト、任意のクラスインスタンス、フォームデータ、バイト配列など、さまざまな種類のペイロードを受け入れます。

テキスト

プレーンテキストをボディとして送信する方法は以下の通りです。

kotlin
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*

val response: HttpResponse = client.post("http://localhost:8080/post") {
    setBody("Body content")
}

オブジェクト

ContentNegotiationプラグインを有効にすると、リクエストボディ内でクラスインスタンスをJSONとして送信できます。これを行うには、クラスインスタンスをsetBody()関数に渡し、contentType()関数を使用してコンテンツタイプをapplication/jsonに設定します。

kotlin
val response: HttpResponse = client.post("http://localhost:8080/customer") {
    contentType(ContentType.Application.Json)
    setBody(Customer(3, "Jet", "Brains"))
}

詳細については、Ktorクライアントにおけるコンテンツネゴシエーションとシリアライゼーションを参照してください。

フォームパラメーター

Ktorクライアントは、application/x-www-form-urlencodedタイプのフォームパラメーターを送信するためのsubmitForm()関数を提供します。以下の例はその使用方法を示しています。

kotlin
val client = HttpClient(CIO)
val response: HttpResponse = client.submitForm(
    url = "http://localhost:8080/signup",
    formParameters = parameters {
        append("username", "JetBrains")
        append("email", "[email protected]")
        append("password", "foobar")
        append("confirmation", "foobar")
    }
)
  • urlはリクエストを行うためのURLを指定します。
  • formParametersparametersを使用して構築されたフォームパラメーターのセットです。

完全な例については、client-submit-formを参照してください。

URLでエンコードされたフォームパラメーターを送信するには、encodeInQuerytrueに設定します。

ファイルのアップロード

フォームでファイルを送信する必要がある場合、次のアプローチを使用できます。

  • .submitFormWithBinaryData()関数を使用します。この場合、境界が自動的に生成されます。
  • post関数を呼び出し、MultiPartFormDataContentインスタンスをsetBody関数に渡します。MultiPartFormDataContentコンストラクターでは、境界値を渡すこともできます。

どちらのアプローチでも、formData {}関数を使用してフォームデータを構築する必要があります。

.submitFormWithBinaryData()の使用

.submitFormWithBinaryData()関数は、境界を自動的に生成し、ファイルの内容が.readBytes()を使用して安全にメモリに読み込めるほど小さい単純なユースケースに適しています。

kotlin
        val client = HttpClient(CIO)

        val response: HttpResponse = client.submitFormWithBinaryData(
            url = "http://localhost:8080/upload",
            formData = formData {
                append("description", "Ktor logo")
                append("image", File("ktor_logo.png").readBytes(), Headers.build {
                    append(HttpHeaders.ContentType, "image/png")
                    append(HttpHeaders.ContentDisposition, "filename=\"ktor_logo.png\"")
                })
            }
        )

完全な例については、client-uploadを参照してください。

MultiPartFormDataContentの使用

大量または動的なコンテンツを効率的にストリーミングするには、InputProviderとともにMultiPartFormDataContentを使用できます。InputProviderを使用すると、ファイルデータ全体をメモリにロードするのではなく、バッファリングされたストリームとして供給できるため、大規模なファイルに適しています。MultiPartFormDataContentを使用すると、onUploadコールバックを使用してアップロードの進行状況を監視することもできます。

kotlin
        val client = HttpClient(CIO)

        val file = File("ktor_logo.png")

        val response: HttpResponse = client.post("http://localhost:8080/upload") {
            setBody(
                MultiPartFormDataContent(
                    formData {
                        append("description", "Ktor logo")
                        append(
                            "image",
                            InputProvider { file.inputStream().asInput().buffered() },
                            Headers.build {
                                append(HttpHeaders.ContentType, "image/png")
                                append(HttpHeaders.ContentDisposition, "filename=\"ktor_logo.png\"")
                            }
                        )
                    },
                    boundary = "WebAppBoundary"
                )
            )
            onUpload { bytesSentTotal, contentLength ->
                println("Sent $bytesSentTotal bytes from $contentLength")
            }
        }

マルチプラットフォームプロジェクトでは、InputProviderとともにSystemFileSystem.source()を使用できます。

kotlin
InputProvider { SystemFileSystem.source(Path("ktor_logo.png")).buffered() }

カスタムの境界とコンテンツタイプを持つMultiPartFormDataContentを手動で構築することもできます。

kotlin
fun customMultiPartMixedDataContent(parts: List<PartData>): MultiPartFormDataContent {
    val boundary = "WebAppBoundary"
    val contentType = ContentType.MultiPart.Mixed.withParameter("boundary", boundary)
    return MultiPartFormDataContent(parts, boundary, contentType)
}

完全な例については、client-upload-progressを参照してください。

バイナリデータ

application/octet-streamコンテンツタイプでバイナリデータを送信するには、ByteReadChannelインスタンスをsetBody()関数に渡します。たとえば、File.readChannel()関数を使用してファイルの読み取りチャネルを開くことができます。

kotlin
val response = client.post("http://0.0.0.0:8080/upload") {
    setBody(File("ktor_logo.png").readChannel())
}

完全な例については、client-upload-binary-dataを参照してください。

並列リクエスト

デフォルトでは、複数のリクエストを順次送信すると、クライアントは前のリクエストが完了するまで各呼び出しを中断(suspend)します。複数のリクエストを同時に実行するには、launch()またはasync()関数を使用します。次の例は、async()を使用して2つのリクエストを並列に実行する方法を示しています。

kotlin
coroutineScope {
    // Parallel requests
    val firstRequest: Deferred<String> = async { client.get("http://localhost:8080/path1").bodyAsText() }
    val secondRequest: Deferred<String> = async { client.get("http://localhost:8080/path2").bodyAsText() }
    val firstRequestContent = firstRequest.await()
    val secondRequestContent = secondRequest.await()
}

完全な例については、client-parallel-requestsを参照してください。

リクエストのキャンセル

リクエストをキャンセルするには、そのリクエストを実行しているコルーチンをキャンセルします。launch()関数は、実行中のコルーチンをキャンセルするために使用できるJobを返します。

kotlin
import kotlinx.coroutines.*

val client = HttpClient(CIO)
val job = launch {
    val requestContent: String = client.get("http://localhost:8080")
}
job.cancel()

詳細については、キャンセルとタイムアウトを参照してください。