- 作者:老汪软件技巧
- 发表时间:2024-11-03 00:02
- 浏览量:
新版本 Ktor 基于 Kotlin 2.0 构建, 并切换到 kotlinx-io, 使 Ktor 与时俱进, 并更好地与其他 Kotlin 工具连接. Ktor 3.0 运行速度更快, 为你提供了更多构建客户端-服务器应用的选项.
今天这篇文章我将将为你详细介绍 Ktor 3.0 的新特性和重要的性能改进.
迁移到 kotlinx-io
新版本中最大的变化是切换到了基于 Okio 的 kotlinx-io 库. 如果你使用 Ktor 的底层 IO API, 这一变更可能会对你产生影响. 正如基准测试所示, 这一改动是为了规范 Kotlin 库中的 IO 功能并提高性能.
破坏性更改
这些更改主要影响底层 IO API, 包括 Input, Output, ByteReadChannel 和 ByteWriteChannel 等类. 如果直接使用这些类, 你将看到弃用警告. 你应该更新代码, 使用 kotlinx-io 库提供的替代类. 别担心, 在 4.0 版之前, 旧的 API会继续得到支持, 让你有充足的时间进行迁移.
新的 kotlinx-io 库提供了多平台 API, 可以处理各种数据源并提供一系列功能, 包括处理文件, 使用压缩等. 更多详情, 请查阅kotlinx-io API 文档.
性能改进
通过改用 kotlinx-io, 我们减少了 ByteReadChannel, ByteWriteChannel 和网络接口之间不必要的字节复制. 这使得字节转换和解析更加高效, 为未来的性能提升留出了空间.
我们的IO 基准 测试基于真实的 Ktor 应用, 结果令人印象深刻. 一些测试结果表明, 性能提高了 90%以上, 我们还在努力进行更多改进.
支持服务器发送事件(SSE)
在 Ktor 3.0 中, 我们为服务器和客户端添加了对服务器发送事件(SSE)的初步支持.
服务器发送事件是一种能让服务器通过 HTTP 连接向客户端推送事件的技术. SSE 提供了从服务器到客户端的单向通信通道. 这种方法适用于服务器需要发送基于事件的更新而不需要客户端反复轮询新信息的情况.
要在 Ktor 应用中实现 SSE 支持, 首先要在项目的构建脚本中添加 SSE 依赖项:
implementation("io.ktor:ktor-server-sse-jvm")
接下来, 在 Ktor 应用中安装 SSE 插件, 并使用 sse{} 函数创建一个端点:
import io.ktor.server.application.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.routing.*
import io.ktor.server.sse.*
import io.ktor.sse.*
import kotlinx.coroutines.delay
fun main() {
embeddedServer(Netty, port = 8080) {
install(SSE)
routing {
sse {
repeat(42) {
val name = call.parameters["name"] ?: "World"
send(ServerSentEvent(data = "Hello, $name! $it"))
delay(1000)
}
close()
}
}
}.start(wait = true)
}
在sse{...}块中, 你可以访问一个具有以下功能的ServerSSESession实例.
请注意, Ktor 目前不支持 SSE 响应的数据压缩. 如果使用压缩插件, 默认情况下会跳过对 SSE 响应的压缩.
要使用 Ktor 客户端消费事件, 在最简单的情况下, 你只需在客户端实例上调用 sse 函数, 如下所示:
import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.plugins.sse.*
import kotlinx.coroutines.runBlocking
fun main() {
val client = HttpClient(CIO) {
install(SSE)
}
runBlocking {
client.sse(host = "127.0.0.1", port = 8080, path = "/sse") {
incoming.collect { event -> println(event) }
}
}
}
在上面的示例中, 只要服务器发送数据, 客户端就会消费事件.
从 ZIP 压缩包中提供静态资源
新函数 staticZip 允许用户将 ZIP 压缩包的内容作为静态内容提供.
下面是一个如何使用它的基本示例:
routing {
staticZip(
remotePath = "/",
basePath = "base",
Path("files/text-files.zip")
) {
default("file.txt")
//modify the response by adding the HTTP Etag header
modify { path, call ->
call.response.headers.append(HttpHeaders.ETag,
path.fileName.toString())
}
}
}
让我们将示例分解为几个关键部分:
remotePath - 访问 ZIP 内容的基本 URL 路径.basePath - 希望提供的 ZIP 文件中的基本路径. 在我们的示例中, 我们假设 ZIP 压缩包包含base目录. 指定的basePath内的所有路径都将通过"remotePath/path/to/resource"递归访问. 这意味着你可以用子文件夹来组织你的 ZIP 文件, 它们将反映在 URL 结构中.Path("files/text-files.zip")- 你要提供的 ZIP 文件的路径.default() 函数 - 如果没有请求特定文件, 可使用该函数指定一个默认文件.modify块 - 这使你可以自定义响应. 在本例中, 我们根据文件名添加了一个 ETag 标头.
想要查看完整示例的话, 你可以参考 GitHub 上的 Ktor 示例代码库.
支持 CSRF
新插件增加了对 CSRF(跨站请求伪造)保护的支持. 对 POST, PUT 和 DELETE 等改变状态的操作启用了保护.
一般来说, 它只适用于使用会话 cookie 和表单的项目, 因为启用该功能会使应用不必要地复杂化.
要在 Ktor 应用中启用 CSRF 支持, 首先要在项目的构建脚本中添加以下依赖项:
implementation("io.ktor:ktor-server-csrf-jvm")
接下来, 你可以为应用中选定的路由启用 CSRF 保护, 如下所示:
route("/csrf") {
install(CSRF) {
allowOrigin("https://localhost:8080")
originMatchesHost()
checkHeader("X-CSRF") { csrfHeader ->
request.headers[HttpHeaders.Origin]?.let { origin ->
csrfHeader == origin.hashCode().toString(32) // 1ndrgg9
} == true
}
onFailure {
respondText("Access denied!", status = HttpStatusCode.Forbidden)
}
}
post {
call.respondText("CSRF check was successful")
}
}
在配置块中, 插件提供了几种验证请求的方法:
如果使用上述代码运行应用, 并使用 curl 命令向 /csrf 端点发送一个 POST 请求, 你将看到以下内容:
curl -X POST -H "Content-Type: application/json" --data '{}' http://localhost:8080/csrf
访问被拒绝了!
添加所需的Header信息将使其通过检查::
curl -X POST -H "X-CSRF: 1ndrgg9" -H "Origin: http://localhost:8080" -H "Content-Type: application/json" --data '{}' http://localhost:8080/csrf
CSRF 检查通过了!
Ktor 客户端支持 Wasm
Ktor 客户端现在支持将 WebAssembly(Wasm)作为构建目标. 虽然 Kotlin/Wasm 仍处于早期阶段(Alpha), 但为 Ktor 客户端添加 Wasm 支持是扩展 Kotlin 多平台生态系统的重要一步. 为了展示这一新功能, 我们创建了一个示例 Compose Multiplatform 项目, 该项目使用带有 WebAssembly (wasmJs) 目标的 Ktor 客户端.
要使用 Ktor 客户端, 你需要在项目的构建脚本中添加相应的依赖关系:
implementation("io.ktor:ktor-client-core:$ktor_version")
迁移指南
Ktor 3.0 带来了一些重大变化. 官方为你准备了一份 迁移指南, 让你更轻松地过渡. 在此, 我们将重点介绍最显著的变化.
无论你是否将现有项目升级到 Ktor 3.0, 你都可以立即开始使用 Ktor 3.0 构建新项目!
在 TestApplication 中明确加载模块
从现在起, TestApplication 类要求显式加载模块. 下面的测试将启动一个空应用, 不会加载任何模块:
@Test
fun testRoot() = testApplication {// TestApplication scope
client.get("/").apply {
assertEquals(HttpStatusCode.OK, status)
assertEquals("Hello World!", bodyAsText())
}
}
相反的是, 你必须在 testApplication 函数中明确加载模块, 或手动加载配置文件.
@Test
fun testRoot() = testApplication {
application {
configureRouting()
}
client.get("/").apply {
assertEquals(HttpStatusCode.OK, status)
assertEquals("Hello World!", bodyAsText())
}
}
插件更新
CallLogging插件包已重命名, 修正了一个错别字:
注意: 请务必启用新的 Resources 插件, 以实现类型安全路由.
这些变更旨在改进已有的 Ktor 的架构及其安全性和开发者体验. 从 Ktor 2.x 升级的用户请参考详细的 迁移指南, 以确保顺利过渡到新版本.
今天的主要内容就是这些啦!
一家之言, 欢迎拍砖!
Happy Coding! Stay GOLDEN!