雖然 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!")
    }
}
除了比較基本的這些事件,還有:
這些事件可以透過 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}")
      }
   }
}
今天的部分就到這邊,我們明天見!