MST
星途 面试题库

面试题:Kotlin Ktor插件的基本使用

请描述在Kotlin的Ktor框架中,如何创建并使用一个简单的自定义插件,比如一个用于记录请求日志的插件。请给出具体代码示例,并解释插件的加载和执行流程。
32.9万 热度难度
编程语言Kotlin

知识考点

AI 面试

面试题答案

一键面试

创建自定义日志记录插件

  1. 定义插件
    import io.ktor.application.*
    import io.ktor.http.*
    import io.ktor.request.*
    import io.ktor.response.*
    import io.ktor.routing.*
    import io.ktor.util.*
    import java.util.Date
    
    class RequestLoggingPlugin(private val logMessage: String) {
        companion object Feature : ApplicationFeature<Application, RequestLoggingPlugin.Config, RequestLoggingPlugin> {
            override val key = AttributeKey<RequestLoggingPlugin>("RequestLoggingPlugin")
            override fun install(pipeline: Application, configure: Config.() -> Unit): RequestLoggingPlugin {
                val config = Config().apply(configure)
                val plugin = RequestLoggingPlugin(config.logMessage)
                pipeline.intercept(ApplicationCallPipeline.Application) {
                    val startTime = Date()
                    call.attributes.put(key, plugin)
                    val requestMethod = call.request.httpMethod.value
                    val requestPath = call.request.uri
                    println("$logMessage - Request received: $requestMethod $requestPath at $startTime")
                    try {
                        proceed()
                    } finally {
                        val endTime = Date()
                        println("$logMessage - Request completed at $endTime. Duration: ${endTime.time - startTime.time} ms")
                    }
                }
                return plugin
            }
    
            data class Config {
                var logMessage: String = "Default Log Message"
            }
        }
    }
    
  2. 使用插件
    fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args)
    
    @Suppress("unused") // Referenced in application.conf
    @kotlin.jvm.JvmOverloads
    fun Application.module(testing: Boolean = false) {
        install(RequestLoggingPlugin) {
            logMessage = "My Request Logging"
        }
        routing {
            get("/") {
                call.respondText("Hello, World!")
            }
        }
    }
    

插件加载和执行流程解释

  1. 加载流程
    • 当在 Application 中调用 install(RequestLoggingPlugin) 时,install 函数会被执行。
    • 首先,Config 对象被创建并应用传入的配置闭包(这里设置了 logMessage)。
    • 然后,RequestLoggingPlugin 实例被创建,并且通过 pipeline.intercept 方法在 ApplicationCallPipeline.Application 阶段插入拦截逻辑。
    • 最后,RequestLoggingPlugin 实例被返回并存储在 ApplicationCall 的属性中(通过 call.attributes.put(key, plugin))。
  2. 执行流程
    • 当一个请求到达时,进入 ApplicationCallPipeline.Application 阶段。
    • 首先,记录请求开始时间,打印请求的方法、路径等信息。
    • 然后,proceed() 方法被调用,它会继续执行管道中的下一个阶段(比如处理路由等)。
    • 当请求处理完成(无论是成功还是异常),会执行 finally 块中的代码,记录请求结束时间和执行时长。