Skip to content

リクエストの処理

Ktorを使用すると、ルートハンドラ内で受信リクエストを処理し、レスポンスを送信できます。リクエストを処理する際に、様々なアクションを実行できます。

一般的なリクエスト情報

ルートハンドラ内で、[call.request](https://api.ktor.io/ktor-server/ktor-server-core/io.ktor.server.application/-application-call/request.html) プロパティを使用してリクエストにアクセスできます。これは [ApplicationRequest](https://api.ktor.io/ktor-server/ktor-server-core/io.ktor.server.request/-application-request/index.html) インスタンスを返し、様々なリクエストパラメータへのアクセスを提供します。例えば、以下のコードスニペットはリクエストURIの取得方法を示しています。

kotlin
routing {
    get("/") {
        val uri = call.request.uri
        call.respondText("Request uri: $uri")
    }
}

[call.respondText](server-responses.md#plain-text) メソッドは、クライアントにレスポンスを送信するために使用されます。

[ApplicationRequest](https://api.ktor.io/ktor-server/ktor-server-core/io.ktor.server.request/-application-request/index.html) オブジェクトを使用すると、例えば以下のような様々なリクエストデータにアクセスできます。

  • ヘッダー
    すべてのリクエストヘッダーにアクセスするには、[ApplicationRequest.headers](https://api.ktor.io/ktor-server/ktor-server-core/io.ktor.server.request/-application-request/headers.html) プロパティを使用します。acceptEncodingcontentTypecacheControl などの専用の拡張関数を使用して、特定のヘッダーにアクセスすることもできます。
  • Cookie
    [ApplicationRequest.cookies](https://api.ktor.io/ktor-server/ktor-server-core/io.ktor.server.request/-application-request/cookies.html) プロパティは、リクエストに関連するCookieへのアクセスを提供します。Cookieを使用したセッションの処理方法については、セッションのセクションを参照してください。
  • 接続の詳細
    ホスト名、ポート、スキームなどの接続の詳細にアクセスするには、[ApplicationRequest.local](https://api.ktor.io/ktor-server/ktor-server-core/io.ktor.server.request/-application-request/local.html) プロパティを使用します。
  • X-Forwarded- ヘッダー
    HTTPプロキシまたはロードバランサーを介して渡されたリクエストに関する情報を取得するには、[Forwarded headers](server-forward-headers.md) プラグインをインストールし、[ApplicationRequest.origin](https://api.ktor.io/ktor-server/ktor-server-core/io.ktor.server.plugins/origin.html) プロパティを使用します。

パスパラメータ

リクエストを処理する際、call.parameters プロパティを使用してパスパラメータの値にアクセスできます。例えば、以下のコードスニペットの call.parameters["login"] は、/user/admin パスに対して admin を返します。

kotlin
get("/user/{login}") {
    if (call.parameters["login"] == "admin") {
        // ...
    }
}

クエリパラメータ

クエリ文字列のパラメータにアクセスするには、[ApplicationRequest.queryParameters](https://api.ktor.io/ktor-server/ktor-server-core/io.ktor.server.request/query-parameters.html) プロパティを使用できます。例えば、/products?price=asc へのリクエストがあった場合、次のように price クエリパラメータにアクセスできます。
kotlin
get("/products") {
    if (call.request.queryParameters["price"] == "asc") {
        // Show products from the lowest price to the highest
    }
}

[ApplicationRequest.queryString](https://api.ktor.io/ktor-server/ktor-server-core/io.ktor.server.request/query-string.html) 関数を使用して、クエリ文字列全体を取得することもできます。

ボディコンテンツ

このセクションでは、POSTPUT、または PATCH で送信されたボディコンテンツを受信する方法を示します。

生のペイロード

生のボディペイロードにアクセスして手動でパースするには、受信するペイロードの型を受け入れる [ApplicationCall.receive](https://api.ktor.io/ktor-server/ktor-server-core/io.ktor.server.request/receive.html) 関数を使用します。 以下のHTTPリクエストがあるとします。

HTTP
POST http://localhost:8080/text
Content-Type: text/plain

Hello, world!

このリクエストのボディは、以下のいずれかの方法で指定された型のオブジェクトとして受信できます。

  • String

    リクエストボディをString値として受信するには、call.receive<String>() を使用します。 [receiveText](https://api.ktor.io/ktor-server/ktor-server-core/io.ktor.server.request/receive-text.html) を使用しても同じ結果が得られます。

    kotlin
    post("/text") {
        val text = call.receiveText()
        call.respondText(text)
    }
  • ByteArray

    リクエストのボディをバイト配列として受信するには、call.receive<ByteArray>() を呼び出します。

    kotlin
            post("/bytes") {
                val bytes = call.receive<ByteArray>()
                call.respond(String(bytes))
            }
  • ByteReadChannel

    call.receive<ByteReadChannel>() または [receiveChannel](https://api.ktor.io/ktor-server/ktor-server-core/io.ktor.server.request/receive-channel.html) を使用して、バイトシーケンスの非同期読み取りを可能にする [ByteReadChannel](https://api.ktor.io/ktor-io/io.ktor.utils.io/-byte-read-channel/index.html) を受信できます。

    kotlin
    post("/channel") {
        val readChannel = call.receiveChannel()
        val text = readChannel.readRemaining().readText()
        call.respondText(text)
    }

    以下のサンプルは、ByteReadChannel を使用してファイルをアップロードする方法を示しています。

    kotlin
    post("/upload") {
        val file = File("uploads/ktor_logo.png")
        call.receiveChannel().copyAndClose(file.writeChannel())
        call.respondText("A file is uploaded")
    }

完全な例は post-raw-data で確認できます。

オブジェクト

Ktorは、リクエストのメディアタイプをネゴシエートし、コンテンツを必要な型のオブジェクトにデシリアライズするための [ContentNegotiation](server-serialization.md) プラグインを提供します。リクエストのコンテンツを受信して変換するには、データクラスをパラメータとして受け入れる [ApplicationCall.receive](https://api.ktor.io/ktor-server/ktor-server-core/io.ktor.server.request/receive.html) 関数を呼び出します。

kotlin

        post("/customer") {
            val customer = call.receive<Customer>()
            customerStorage.add(customer)
            call.respondText("Customer stored correctly", status = HttpStatusCode.Created)

詳細については、Ktorサーバーでのコンテンツネゴシエーションとシリアライゼーション を参照してください。

フォームパラメータ

Ktorは、[receiveParameters](https://api.ktor.io/ktor-server/ktor-server-core/io.ktor.server.request/receive-parameters.html) 関数を使用して、x-www-form-urlencoded および multipart/form-data 型の両方で送信されたフォームパラメータを受信できます。以下の例は、ボディにフォームパラメータを渡す [HTTP client](https://www.jetbrains.com/help/idea/http-client-in-product-code-editor.html)POST リクエストを示しています。

HTTP
POST http://localhost:8080/signup
Content-Type: application/x-www-form-urlencoded

username=JetBrains&[email protected]&password=foobar&confirmation=foobar

コード内でパラメータ値を次のように取得できます。

kotlin
post("/signup") {
    val formParameters = call.receiveParameters()
    val username = formParameters["username"].toString()
    call.respondText("The '$username' account is created")
}

完全な例は post-form-parameters で確認できます。

マルチパートフォームデータ

マルチパートリクエストの一部として送信されたファイルを受信するには、[.receiveMultipart()](https://api.ktor.io/ktor-server/ktor-server-core/io.ktor.server.request/receive-multipart.html) 関数を呼び出し、必要に応じて各パートをループ処理します。

マルチパートリクエストデータは順次処理されるため、特定のパートに直接アクセスすることはできません。さらに、これらのリクエストには、フォームフィールド、ファイル、バイナリデータなど、異なる種類のパートが含まれる場合があり、それぞれ異なる方法で処理する必要があります。

この例は、ファイルを受信してファイルシステムに保存する方法を示しています。

kotlin
import io.ktor.server.application.*
import io.ktor.http.content.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import io.ktor.util.cio.*
import io.ktor.utils.io.*
import java.io.File

fun Application.main() {
    routing {
        post("/upload") {
            var fileDescription = ""
            var fileName = ""
            val multipartData = call.receiveMultipart(formFieldLimit = 1024 * 1024 * 100)

            multipartData.forEachPart { part ->
                when (part) {
                    is PartData.FormItem -> {
                        fileDescription = part.value
                    }

                    is PartData.FileItem -> {
                        fileName = part.originalFileName as String
                        val file = File("uploads/$fileName")
                        part.provider().copyAndClose(file.writeChannel())
                    }

                    else -> {}
                }
                part.dispose()
            }

            call.respondText("$fileDescription is uploaded to 'uploads/$fileName'")
        }
    }
}

デフォルトのファイルサイズ制限

デフォルトでは、受信できるバイナリおよびファイルアイテムの許可されるサイズは50MBに制限されています。受信したファイルまたはバイナリアイテムが50MBの制限を超えると、IOException がスローされます。

デフォルトのフォームフィールド制限をオーバーライドするには、.receiveMultipart() を呼び出す際に formFieldLimit パラメータを渡します。

kotlin
val multipartData = call.receiveMultipart(formFieldLimit = 1024 * 1024 * 100)

この例では、新しい制限が100MBに設定されています。

フォームフィールド

PartData.FormItem はフォームフィールドを表し、その値は value プロパティを通じてアクセスできます。

kotlin
when (part) {
    is PartData.FormItem -> {
        fileDescription = part.value
    }
}

ファイルアップロード

PartData.FileItem はファイルアイテムを表します。ファイルアップロードはバイトストリームとして処理できます。

kotlin
when (part) {
    is PartData.FileItem -> {
        fileName = part.originalFileName as String
        val file = File("uploads/$fileName")
        part.provider().copyAndClose(file.writeChannel())
    }
}

[.provider()](https://api.ktor.io/ktor-http/io.ktor.http.content/-part-data/-file-item/provider.html) 関数は ByteReadChannel を返し、これによりデータを増分的に読み取ることができます。 .copyAndClose() 関数を使用することで、適切なリソースクリーンアップを保証しながら、ファイルコンテンツを指定された宛先に書き込みます。

アップロードされたファイルのサイズを決定するには、post ハンドラ内で Content-Length ヘッダー値を取得できます。

kotlin
post("/upload") {
    val contentLength = call.request.header(HttpHeaders.ContentLength)
    // ...
}

リソースのクリーンアップ

フォーム処理が完了すると、各パートは .dispose() 関数を使用してリソースを解放するために破棄されます。

kotlin
part.dispose()

このサンプルの実行方法については、upload-file を参照してください。