iT邦幫忙

2022 iThome 鐵人賽

DAY 19
0
Mobile Development

Kotlin 全面啟動 系列 第 19

[Kotlin 全面啟動] Ktor Client II

  • 分享至 

  • xImage
  •  

有了 HttpClient 這個物件之後,再來就是實際的連線囉,我們這邊以 Github 的 api 為例:

GET: https://api.github.com/users/<USERNAME>

Request

如果大家有喜歡看原始碼的習慣可能會發現整個 HttpClient 的 class 裡其實除了一個 execute function 以外,沒有任何直接跟連線有關的程式碼,這也有點像是 Kotlin 的 convention,因為有了 extension function 的幫助,我們可以在 class 的外部寫很多 helper function 讓我們更容易使用,同時又可以保持 class 核心功能的簡潔,不過那我們要怎麼真的建立一個連線呢?

其實只要呼叫 request 就可以了,範例如下:

val response: HttpResponse = client.request("https://api.github.com/users/$userName") {
    // extra config
}

點擊 request 進去會發現 request 的確就是一個 extension function,而且它實際上也是呼叫其他的 extension function:

public suspend inline fun HttpClient.request(
    urlString: String,
    block: HttpRequestBuilder.() -> Unit = {}
): HttpResponse = request {
    url(urlString)
    block()
}

public suspend inline fun HttpClient.request(block: HttpRequestBuilder.() -> Unit): HttpResponse =
    request(HttpRequestBuilder().apply(block))

public suspend inline fun HttpClient.request(
    builder: HttpRequestBuilder = HttpRequestBuilder()
): HttpResponse = HttpStatement(builder, this).execute()
  • 一連串一直 call 到 HttpStatement 的內部,又會再 call HttpClientexecute 喔,但這部分就留給讀者們自行探索囉。

HttpMethod

request 本身是怎麼區分 HttpMethod 是 GET 還是 POST 的呢?

在上面這一連串 call 裡面有個 HttpRequestBuilder,讓我們點進去看一下:

public class HttpRequestBuilder : HttpMessageBuilder {
    /**
     * [URLBuilder] to configure the URL for this request.
     */
    public val url: URLBuilder = URLBuilder()

    /**
     * [HttpMethod] used by this request. [HttpMethod.Get] by default.
     */
    public var method: HttpMethod = HttpMethod.Get

    /**
     * [HeadersBuilder] to configure the headers for this request.
     */
    override val headers: HeadersBuilder = HeadersBuilder()
...

由上述程式碼我們可以發現,原來 HttpMethod 預設就是 GET 啊,難怪我們不需要設定,如果要改成 POST 也可以直接在這個 lambda block 做改變:

client.request("https://<your path here>"){
    // change HttpMethod
    method = HttpMethod.Post
}
  • 如果要設定 header 參數也是在這個 block 裡改喔!

GET、POST 等 HttpMethod 都算是蠻常用的一些 config,所以 Ktor 其實也提供了另一系列的 extension function,可以把 request 直接換成 getpost 就可以不需要額外設定了:

client.get("https://<your path here>")
client.post("https://<your path here>")

Response

根據我們之前的內容,我們可以把我們的 API 改成這樣的形式:

val response: HttpResponse = client.get("https://api.github.com/users/$userName")

再來就讓我們看看 HttpResponse 是什麼,跟我們想要的結果有什麼不同!

Http Status

首先,一個連線我們必須要掌握的是他的 status code,是正常、失敗還是其他的狀態,在 Ktor 只要直接呼叫 status.value 就可以了:

val response: HttpResponse = client.get("https://api.github.com/users/$userName")
if (response.status.value in 200..299) {
    println("Successful response!")
}

Body

HttpResponse 裡面也有一個 body 的 function 可以回傳連線的結果,有趣的是這個 function 的宣告:

public suspend inline fun <reified T> HttpResponse.body(): T = call.bodyNullable(typeInfo<T>()) as T

回傳的型別是 T,而這個 T 會一路帶下去做檢查以及轉換,所以使用的時候非常簡單,不管你是想要 String 還是 ByteArray

val response: HttpResponse = client.get("https://api.github.com/users/$userName")
val stringBody: String = response.body()
val byteArrayBody: ByteArray = response.body()

值得一提的是這個 T 也不是萬能的,畢竟你傳入一個他不知道怎麼對應的型別,它除了拋出錯誤也沒其他方式可以處理了對吧,那問題就回到怎麼讓他可以支援我們想要的型別了!


上一篇
[Kotlin 全面啟動] Ktor Client
下一篇
[Kotlin 全面啟動] Ktor Client III
系列文
Kotlin 全面啟動 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言