iT邦幫忙

2023 iThome 鐵人賽

DAY 4
1

昨天我們看過了預設程式碼內 routing() 的實作

routing {
	get("/") {
		call.respondText("Hello World!")
	}
}

看完 routing() 的實作之後,下一步我們來看 get() 函數的實作。

get() 函數可以在 Ktor 框架內幫我們定義一個接收 GET 請求的路由,實作如下

/**
 * Builds a route to match `GET` requests with the specified [path].
 * @see [Application.routing]
 */
@KtorDsl
public fun RoutingBuilder.get(path: String, body: RoutingHandler): RoutingBuilder {
    return route(path, HttpMethod.Get) { handle(body) }
}

粗略地看,可以看出這邊做的事情就是使用 route 函數,搭配 HttpMethod.Get,來建立一個 GET 的路由。

不過細心的讀者可能會發現:body 應該要是一個函數,才能允許程式內使用 {} 定義內容。這邊的寫法 RoutingHandler,好像是一個介面或者類別一樣?

我們來看看 RoutingHandler 的實作:

public typealias RoutingHandler = suspend RoutingContext.() -> Unit

我們會發現如前面所說,body 確實是一個函數沒錯,不過為了讓程式看起來更加好懂,這邊利用了 Kotlin 的 typealias 關鍵字,將 RoutingHandler 定義成了 suspend RoutingContext.() -> Unit 的同義詞。

另外我們也會發現,這個函數標記了 suspend 關鍵字,所以這會是一個可以用 Coroutine 暫停的函數。

下一段,我們來看 route() 的實作

@KtorDsl
public fun RoutingBuilder.route(path: String, method: HttpMethod, build: RoutingBuilder.() -> Unit): RoutingBuilder {
    val selector = HttpMethodRouteSelector(method)
    return createRouteFromPath(path).createChild(selector).apply(build)
}

根據 HttpMethodRouteSelector 的命名,我們可以猜這是用來篩選請求是否跟設定的 HTTP Method 一致。

我們來看看,實際上是不是我們所想的這樣:

public data class HttpMethodRouteSelector(
    val method: HttpMethod
) : RouteSelector() {

    override fun evaluate(context: RoutingResolveContext, segmentIndex: Int): RouteSelectorEvaluation {
        if (context.call.request.httpMethod == method) {
            return RouteSelectorEvaluation.Constant
        }
        return RouteSelectorEvaluation.FailedMethod
    }

    override fun toString(): String = "(method:${method.value})"
}

可能有點出乎意料,HttpMethodRouteSelector 竟然是一個 data class!這邊利用了 data class 幫忙實作 setter 的部分,所以我們只需要實作判斷的 evaluate()。如果請求的 method 和設置的 method 相同,這邊會回傳 RouteSelectorEvaluation.Constant,定義如下:

/**
 * Route evaluation succeeded for a constant value.
 */
public val Constant: RouteSelectorEvaluation =            RouteSelectorEvaluation.Success(RouteSelectorEvaluation.qualityConstant)

如果比對不相同,則改回傳 RouteSelectorEvaluation.FailedMethod

看過了 HttpMethodRouteSelector,我們明天再來看看

return createRouteFromPath(path).createChild(selector).apply(build)

這一段程式碼,是怎麼處理我們輸入的路徑的


上一篇
Day 03:設置路由 `Application.configureRouting()`
下一篇
Day 05:路由元素的分析,看 route() 後半段的實作內容
系列文
深入解析 Kotlin 專案 Ktor 的程式碼,探索 Ktor 的強大功能30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言