リクエストの送信
コード例: client-configure-request
クライアントの設定後、HTTPリクエストの送信を開始できます。これを行う主な方法は、URLをパラメーターとして受け取る.request()
関数を使用することです。この関数内で、さまざまなリクエストパラメーターを設定できます。
GET
、POST
、PUT
、DELETE
、HEAD
、OPTIONS
、PATCH
などのHTTPメソッドを指定します。- URLを文字列として設定するか、そのコンポーネント(ドメイン、パス、クエリパラメーターなど)を個別に設定します。
- Unixドメインソケットを使用します。
- ヘッダーとCookieを追加します。
- リクエストボディ(例:プレーンテキスト、データオブジェクト、フォームパラメーター)を含めます。
これらのパラメーターはHttpRequestBuilder
クラスによって公開されます。
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メソッドを指定できます。
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()
関数を使用すると簡略化できます。
val response: HttpResponse = client.get("https://ktor.io/docs/welcome.html")
どちらの例でも、リクエストURLは文字列として指定されています。HttpRequestBuilder
を使用してURLコンポーネントを個別に設定することもできます。
リクエストURLの指定
Ktorクライアントでは、さまざまな方法でリクエストURLを設定できます。
URL文字列全体を渡す
val response: HttpResponse = client.get("https://ktor.io/docs/welcome.html")
URLコンポーネントを個別に設定する
client.get {
url {
protocol = URLProtocol.HTTPS
host = "ktor.io"
path("docs/welcome.html")
}
}
この場合、HttpRequestBuilder
によって提供されるurl
パラメーターが使用されます。これはURLBuilder
のインスタンスを受け入れ、複雑なURLを構築するためのより多くの柔軟性を提供します。
すべてのリクエストのベースURLを設定するには、
DefaultRequest
プラグインを使用します。
パスセグメント
前の例では、URLBuilder.path
プロパティを使用してURLパス全体が指定されました。または、appendPathSegments()
関数を使用して個々のパスセグメントを渡すこともできます。
client.get("https://ktor.io") {
url {
appendPathSegments("docs", "welcome.html")
}
}
デフォルトでは、appendPathSegments
はパスセグメントをエンコードします。エンコーディングを無効にするには、代わりにappendEncodedPathSegments()
を使用します。
クエリパラメーター
クエリ文字列パラメーターを追加するには、URLBuilder.parameters
プロパティを使用します。client.get("https://ktor.io") {
url {
parameters.append("token", "abc123")
}
}
デフォルトでは、parameters
はクエリパラメーターをエンコードします。エンコーディングを無効にするには、代わりにencodedParameters()
を使用します。
trailingQuery
プロパティは、クエリパラメーターがない場合でも?
文字を保持するために使用できます。
URLフラグメント
ハッシュマーク#
は、URLの末尾近くにオプションのフラグメントを導入します。fragment
プロパティを使用してURLフラグメントを設定できます。
client.get("https://ktor.io") {
url {
fragment = "some_anchor"
}
}
デフォルトでは、fragment
はURLフラグメントをエンコードします。エンコーディングを無効にするには、代わりにencodedFragment()
を使用します。
Unixドメインソケットの指定
Unixドメインソケットは、CIOエンジンでのみサポートされています。 KtorサーバーでUnixソケットを使用するには、それに応じてサーバーを設定します。
Unixドメインソケットをリッスンしているサーバーにリクエストを送信するには、CIOクライアントを使用する際にunixSocket()
関数を呼び出します。
val client = HttpClient(CIO)
val response: HttpResponse = client.get("/") {
unixSocket("/tmp/test-unix-socket-ktor.sock")
}
デフォルトのリクエストの一部としてUnixドメインソケットを設定することもできます。
リクエストパラメーターの設定
HTTPメソッド、ヘッダー、Cookieなど、さまざまなリクエストパラメーターを指定できます。特定のクライアントのすべてのリクエストに対してデフォルトのパラメーターを設定する必要がある場合は、DefaultRequest
プラグインを使用します。
ヘッダー
リクエストにヘッダーを追加する方法はいくつかあります。
複数のヘッダーを追加する
headers
関数を使用すると、一度に複数のヘッダーを追加できます。
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()
関数を使用します。
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()
関数を呼び出します。この関数は、プレーンテキスト、任意のクラスインスタンス、フォームデータ、バイト配列など、さまざまな種類のペイロードを受け入れます。
テキスト
プレーンテキストをボディとして送信する方法は以下の通りです。
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
に設定します。
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()
関数を提供します。以下の例はその使用方法を示しています。
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を指定します。formParameters
はparameters
を使用して構築されたフォームパラメーターのセットです。
完全な例については、client-submit-formを参照してください。
URLでエンコードされたフォームパラメーターを送信するには、
encodeInQuery
をtrue
に設定します。
ファイルのアップロード
フォームでファイルを送信する必要がある場合、次のアプローチを使用できます。
.submitFormWithBinaryData()
関数を使用します。この場合、境界が自動的に生成されます。post
関数を呼び出し、MultiPartFormDataContent
インスタンスをsetBody
関数に渡します。MultiPartFormDataContent
コンストラクターでは、境界値を渡すこともできます。
どちらのアプローチでも、formData {}
関数を使用してフォームデータを構築する必要があります。
.submitFormWithBinaryData()
の使用
.submitFormWithBinaryData()
関数は、境界を自動的に生成し、ファイルの内容が.readBytes()
を使用して安全にメモリに読み込めるほど小さい単純なユースケースに適しています。
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
コールバックを使用してアップロードの進行状況を監視することもできます。
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()
を使用できます。
InputProvider { SystemFileSystem.source(Path("ktor_logo.png")).buffered() }
カスタムの境界とコンテンツタイプを持つMultiPartFormDataContent
を手動で構築することもできます。
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()
関数を使用してファイルの読み取りチャネルを開くことができます。
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つのリクエストを並列に実行する方法を示しています。
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
を返します。
import kotlinx.coroutines.*
val client = HttpClient(CIO)
val job = launch {
val requestContent: String = client.get("http://localhost:8080")
}
job.cancel()
詳細については、キャンセルとタイムアウトを参照してください。