[Ktor] 2. Request

[Ktor] 2. Request

Ktor Client ๊ฐ€์ด๋“œ ์š”์•ฝ ์ •๋ฆฌ



HttpClient์˜ request ํ•จ์ˆ˜๋กœ HTTP Request๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

  • request ํ•จ์ˆ˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜ - ๋Œ€ํ‘œ์ ์ธ ์˜ˆ์‹œ
inline suspend fun <T> HttpClient.request(urlString: String, block: HttpRequestBuilder.() -> Unit = {}): T

inline suspend fun <T> HttpClient.request(builder: HttpRequestBuilder = HttpRequestBuilder()): T
  • ์ด์™ธ ๋ชจ๋“  ํ•จ์ˆ˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋Š” ์—ฌ๊ธฐ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

HttpRequestBuilder๋ฅผ ํ†ตํ•ด HTTP method, ํ—ค๋”, ์ฟ ํ‚ค, ๋ฐ”๋”” ๋“ฑ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

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

Request ํŒŒ๋ผ๋ฏธํ„ฐ

> HTTP method

  1. request ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ method ํ”„๋กœํผํ‹ฐ๋ฅผ ํ†ตํ•ด HTTP method๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
  2. val response: HttpResponse = client.request("https://ktor.io/") { method = HttpMethod.Get }
  3. request ํ•จ์ˆ˜ ์™ธ์— HttpClient๋Š” ๊ฐ method ๋ณ„ ๊ธฐ๋ณธ ํ•จ์ˆ˜๋ฅผ ์ œ๊ณตํ•œ๋‹ค. - get, post, put ๋“ฑ
  4. val response: HttpResponse = client.get("https://ktor.io/")

> ํ—ค๋”

headers ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด Request์— ํ—ค๋”๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

fun HttpRequestBuilder.headers(block: HeadersBuilder.() -> Unit): HeadersBuilder
val response: HttpResponse = client.get("https://ktor.io/") {
    headers {
        append(HttpHeaders.Accept, "text/html")
        append(HttpHeaders.Authorization, "token")
        append(HttpHeaders.UserAgent, "ktor client")
    }
}

> ์ฟ ํ‚ค

์ฟ ํ‚ค ์ „์†ก์€ cookie ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•œ๋‹ค.

fun HttpRequestBuilder.cookie(
    name: String,
    value: String,
    maxAge: Int = 0,
    expires: GMTDate? = null,
    domain: String? = null,
    path: String? = null,
    secure: Boolean = false,
    httpOnly: Boolean = false,
    extensions: Map<String, String?> = emptyMap()
)
val response: HttpResponse = 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 = 2022
    ))
}

*ํ˜ธ์ถœ ๊ฐ„ ์ฟ ํ‚ค๋ฅผ ์œ ์ง€ํ•ด์ฃผ๋Š” Cookiesํ”Œ๋Ÿฌ๊ทธ์ธ๋„ ์ œ๊ณตํ•œ๋‹ค.

> Query parameters

parameter ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ ์ถ”๊ฐ€ํ•œ๋‹ค.

fun HttpRequestBuilder.parameter(key: String, value: Any?)
val response: HttpResponse = client.get("http://localhost:8080/products") {
    parameter("price", "asc")
}

Request body

Request body๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด HttpRequestBuilder์˜
body ํ”„๋กœํผํ‹ฐ๋ฅผ ์ด์šฉํ•ด์•ผ ํ•œ๋‹ค. body ํ”„๋กœํผํ‹ฐ๋Š” ํ…์ŠคํŠธ / ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค / form data ๋“ฑ ์—ฌ๋Ÿฌ ํƒ€์ž…์„ ์ง€์›ํ•œ๋‹ค. (ํƒ€์ž…์ด Any์ธ ๊ฒƒ์œผ๋กœ ์•Œ ์ˆ˜ ์žˆ๋‹ค.)

var body: Any

์˜ˆ์‹œ) ํ…์ŠคํŠธ

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

์˜ˆ์‹œ) ๊ฐ์ฒด

Json ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•˜๋ฉด ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๋ฅผ Json ํ˜•์‹์œผ๋กœ body์— ๋„ฃ์„ ์ˆ˜ ์žˆ๋‹ค. body ํ”„๋กœํผํ‹ฐ์— ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๋ฅผ ๋„ฃ๊ณ , content type์„ application.json์œผ๋กœ ์„ค์ •ํ•˜๋ฉด ๋œ๋‹ค.

client.post<Unit>("http://localhost:8080/post") {
    contentType(ContentType.Application.Json)
    body = Customer("Jet", "Brains")
}

์˜ˆ์‹œ) Form data

submitForm ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ x-www-form-urlencoded ๊ณผ multipart/form-data ํƒ€์ž…์˜ form data ์ „์†ก์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

val response: HttpResponse = client.submitForm(
    url = "http://localhost:8080/get",
    formParameters = Parameters.build {
        append("first_name", "Jet")
        append("last_name", "Brains")
    },
    encodeInQuery = true
)

์˜ˆ์‹œ) ํŒŒ์ผ ์—…๋กœ๋“œ

submitFormWithBinaryData ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ form data์— ํŒŒ์ผ์„ ํฌํ•จ์‹œํ‚จ๋‹ค. (์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ ์˜ˆ์ œ๋Š” ์—ฌ๊ธฐ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.)

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")
        })
    }
) {
      // onUpload ํ™•์žฅํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜๋ฉด ์—…๋กœ๋“œ progress ํ‘œ์‹œ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.
    onUpload { bytesSentTotal, contentLength ->
        println("Sent $bytesSentTotal bytes from $contentLength")
    }
}

๋ณ‘๋ ฌ ์š”์ฒญ

๋‘ ๊ฐœ์˜ ์š”์ฒญ์„ ํ•œ ๋ฒˆ์— ๋ณด๋‚ด๋Š” ๊ฒฝ์šฐ, HttpClient๋Š” ์ฒซ ๋ฒˆ์งธ ์š”์ฒญ์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ๋‘ ๋ฒˆ์งธ ์š”์ฒญ์„ ๋Œ€๊ธฐ์‹œํ‚จ๋‹ค. ๋งŒ์•ฝ ์—ฌ๋Ÿฌ ์š”์ฒญ์„ ํ•œ ๋ฒˆ์— ๋ณด๋‚ด๊ณ  ์‹ถ๋‹ค๋ฉด, launch ๋˜๋Š” async ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•œ๋‹ค.
์•„๋ž˜ ์ฝ”๋“œ๋Š” ๋‘ ์š”์ฒญ์„ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์‹คํ–‰ํ•œ๋‹ค (์ „์ฒด ์ƒ˜ํ”Œ ์ฐธ๊ณ  ๋งํฌ):

val client = HttpClient(CIO)
val firstRequest: Deferred<String> = async { client.get("http://localhost:8080/path1") }
val secondRequest: Deferred<String> = async { client.get("http://localhost:8080/path2") }
val firstRequestContent = firstRequest.await()
val secondRequestContent = secondRequest.await()

์š”์ฒญ ์ทจ์†Œ

launch ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜ํ•œ Job์„ ์ด์šฉํ•˜์—ฌ ์ทจ์†Œํ•œ๋‹ค.

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

Comments