Ktor logo

Ktor

Building Asynchronous Servers and Clients in Kotlin

Ktor News Releases

Ktor 3.6.0 正式发布!

Read this post in other languages:

Ktor 3.6.0 来了!此版本包含多项全新实验性功能,包括类型化身份验证能力、针对 OpenID Connect 的专门支持,以及 Netty 引擎的 HTTP/3 支持。此外,路由与请求处理也迎来了一些易用性改进,Kotlin 多平台客户端获得了更便捷的默认配置,另有更多更新。完整变更列表请参阅我们网站上的 Ktor 3.6.0 新功能,或查看发布说明。

🚀 开始使用 Ktor 3.6.0

准备好探索 Ktor 3.6.0 了吗?使用 start.ktor.io 交互式项目生成器,开启你的下一个项目。我们始终欢迎你的反馈和贡献!

类型化身份验证

过去,Ktor 的身份验证依靠隐式类型将配置与路由关联起来。这个模块引入了新类型,确保在处理复杂身份验证时具备完整的类型安全;同时支持基于角色的访问控制和匿名用户。借助上下文参数,语法也更加简洁优雅。有关设置、角色检查和失败处理,请阅读类型安全身份验证文档

val jwtAuth = jwt<User>("my-jwt") {
    verifier(jwkProvider, issuer)
    validate { credential ->
        val payload = credential.payload
        User(
            id = payload.subject,
            email = payload.getClaim("email").asString()
        )
    }
}

routing {
    authenticateWith(jwtAuth) {
        get("/profile") {
            val user = call.principal
            call.respondText(user)
        }
    }
}

OpenID Connect

全新的 OpenID Connect(Oidc)插件旨在降低通过 OpenID Connect 提供方保护服务时的复杂性。Oidc 插件允许你创建类型化身份验证提供方,并以类型安全的方式支持 OpenID Connect 的全部功能。此外还支持会话、具备令牌自动刷新功能的浏览器登录界面等。完整文档请查看 Ktor 网站

suspend fun Application.module() {
    val oidc = install(Oidc)

    val auth0 = oidc.identityProvider("auth0") {
        issuer = "https://my-tenant.auth0.com"
        bearer {
            audience = setOf("https://api.example.com")
        }
    }

    routing {
        authenticateWith(auth0.jwtBearer) {
            get("/orders") {
                val subject = call.principal.claims.subject
                call.respondText("Hello $subject")
            }
        }
    }
}

Netty 的更多功能 

Netty 服务端引擎现已通过 QUIC 提供实验性 HTTP/3 支持。若要启用,请配置 SSL 连接器,然后通过 enableHttp3 { } 选择启用:

embeddedServer(Netty, environment, {
    sslConnector(
        keyStore = keyStore,
        keyAlias = "server",
        keyStorePassword = { "changeit".toCharArray() },
        privateKeyPassword = { "changeit".toCharArray() }
    ) { port = 8443 }

    enableHttp3 { quicMaxIdleTimeout = 30.seconds }
}) { /* application */ }.start(wait = true)

enableHttp3 {} 代码块还允许你调整 QUIC 专用设置,例如流量控制限制和 UDP 套接字配置。此功能仍处于实验阶段;如果你决定试用,欢迎反馈。

Netty 服务器现在还可以在一个连接器上提供 h2c,并在另一个连接器上通过 TLS 提供 HTTP/2。使用 enableH2c = trueenableHttp2 = true 可同时启用二者。

embeddedServer(Netty, configure = {
    connector { port = 8080 }
    sslConnector(...) { port = 8443 }

    enableHttp2 = true
    enableH2c = true
}) { /* application */ }.start(wait = true)

更高效的路由处理器

请求参数转换现已支持 Kotlin 的 UuidByte 和无符号数值类型。ApplicationCall.receive() 现在也接受可空类型,使路由契约更加明确,同时弃用 receiveNullable()

put("/users/{id}") {
    val id: Uuid by call.parameters
    val preferences = call.receive<NotificationPreferences?>()

    if (preferences == null) {
        preferenceService.clear(id)
    } else {
        preferenceService.update(id, preferences)
    }
    call.respond(HttpStatusCode.NoContent)
}

我们还新增了 respondHtmlPartial,用于取代已弃用的 respondHtmlFragment。新函数使用 TagConsumer<Appendable>,因此可以响应不受限制的局部 HTML,并支持 FlowContent 提供的全部元素。

get("/status") {
    call.respondHtmlPartial(HttpStatusCode.OK) {
        td { +"Ready" }
    }
}

更灵活地控制 ContentNegotiation

客户端 ContentNegotiation 插件过去会把已注册的内容类型合并到每个 Accept 请求头中。这通常很有帮助,但如果 API 要求请求中显式设置的请求头保持原样,就并不合适。

使用 ContentTypeMergeStrategy.SkipIfPresent 时,显式 Accept 请求头优先。若请求没有 Accept 请求头,插件仍会像往常一样添加已注册的内容类型:

install(ContentNegotiation) {
    register(ContentType.Application.Json, noOpJsonConverter)
    acceptHeaderMergeStrategy = ContentTypeMergeStrategy.SkipIfPresent
}

简化 Kotlin 多平台客户端

Ktor 3.6.0 引入了 ktor-client-engine-defaults:一组为 Kotlin 多平台项目精选的客户端引擎。将其添加到 commonMain 后,即可在共享代码中创建 HttpClient(),无需选择引擎。Ktor 会为每个目标平台选择合适的可用引擎。

HTTP 缓存也采用了同样的思路。基于文件的缓存存储现在使用 kotlinx-ioPath,因此持久化 HttpCache 存储不再局限于 JVM 的 java.io.File API。结合这些改进,使用简单缓存配置 KMP 客户端变得轻松许多:

// build.gradle.kts
kotlin {
    sourceSets {
        commonMain {
            dependencies {
                api("io.ktor:ktor-client-engine-defaults:3.6.0")
            }
        }
    }
}

// Main.kt
val client = HttpClient() {
    install(HttpCache) {
        publicStorage(FileStorage(Path("build/cache")))
    }
}

这让 Ktor 项目拥有更自然的通用代码配置方式,同时仍可在某个平台需要时选择并配置特定引擎。

3.6.0 的完整变更列表还包括 JVM 的 WebRTC 支持、CIO 异步 DNS 解析、OpenAPI 标签描述、重复 Cookie 解析,以及 JavaScript fetch() 覆盖等内容。详情请参阅 Ktor 3.6.0 新功能

🙏 感谢!

感谢社区中的每一位成员。你们的反馈、问题报告和贡献让每个 Ktor 版本都变得更好。特别感谢工作成果被纳入此版本的外部贡献者:kdelay、Rafa Ruiz 和 solo。

前往 start.ktor.io 开始构建你的下一个项目。我们始终欢迎你的建议和贡献!

👉 开始使用 Ktor | 💬 在 Slack 上加入社区


本博文英文原作者:Simon Vergauwen

本文由 AI 辅助翻译,并经人工审校。如发现任何问题,欢迎在评论区留言指正。