iT邦幫忙

2025 iThome 鐵人賽

DAY 29
0

雖然 Ktor 官方已經提供了大量的套件,加上許多的第三方提供套件,基本上已經涵蓋了許多的功能。

不過,如果你有某一些需求,是常常會出現在不同專案內,並且現有的套件無法滿足的話。

立基於 Ktor 功能均以套件引入的設計架構,Ktor 也允許你自定義自己的套件,讓管理功能變得更加容易

參考 https://openaidoc.org/zh-Hant/ktor/server-custom-plugins

我們可以用 createApplicationPlugin 建立套件的物件

import io.ktor.server.application.*

val SimplePlugin = createApplicationPlugin(name = "SimplePlugin") {
    println("SimplePlugin is installed!")
}

之後我們就可以用前面安裝套件一樣的方式,來安裝這個套件

fun Application.module() {
    install(SimplePlugin)
}

作為後端服務的套件,我們可以針對幾個事件進行設定

  • onCall:取得請求/回應資訊、修改回應參數。
  • onCallReceive:取得並轉換從用戶端接收的資料。
  • onCallRespond:在將資料傳送給用戶端之前進行轉換。

這些比較常見的事件都有對應的函式,可以直接呼叫使用

val CustomHeaderPlugin = createApplicationPlugin(name = "CustomHeaderPlugin") {
    onCall { call ->
        call.response.headers.append("X-Custom-Header", "Hello, world!")
    }
}

除了比較基本的這些事件,還有:

  • CallSetup:處理呼叫的第一步。
  • ResponseBodyReadyForSend:在回應主體經過所有轉換並準備好傳送時觸發。
  • ResponseSent:在回應成功傳送給用戶端時觸發。
  • CallFailed:在呼叫因異常而失敗時觸發。
  • AuthenticationChecked:在驗證憑證檢查後觸發。

這些事件可以透過 on 函式處理

val AuthorizationPlugin = createRouteScopedPlugin(
    name = "AuthorizationPlugin",
    createConfiguration = ::PluginConfiguration
) {
    val roles = pluginConfig.roles
    val getRole = pluginConfig.getRole
    pluginConfig.apply {
        on(AuthenticationChecked) { call ->
            val userName = call.principal<UserIdPrincipal>()?.name
            val userRole = getRole(userName)
            if (userRole !in roles) {
                call.respondText("You are not allowed to visit this page", status = HttpStatusCode.Forbidden)
            }
        }
    }
}

class PluginConfiguration {
    var roles: Set<String> = emptySet()
    lateinit var getRole : (userName: String?) -> String
}

如果需要存取 Application 內的伺服器設定,我們可以使用 applicationConfig 取得

val SimplePlugin = createApplicationPlugin(name = "SimplePlugin") {
   val host = applicationConfig?.host
   val port = applicationConfig?.port
   println("Listening on $host:$port")
}

環境則是由 environment 取得

val SimplePlugin = createApplicationPlugin(name = "SimplePlugin") {
   val isDevMode = environment?.developmentMode
   onCall { call ->
      if (isDevMode == true) {
         println("handling request ${call.request.uri}")
      }
   }
}

今天的部分就到這邊,我們明天見!


上一篇
Day 28:Exposed 在 Ktor 內的自動化測試
下一篇
Day 30:Ktor 3 的介紹總結
系列文
每天一點 Ktor 3.0:一個月學會 Kotlin 後端開發30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言