Ktor 入门指南:快速了解并上手开发
序言:Kotlin 在服务器端的崛起与 Ktor 的地位
随着 Kotlin 语言的日益普及,它不仅在 Android 开发领域占据了主导地位,在后端开发领域也展现出了巨大的潜力。Kotlin 的简洁语法、强大的类型推断、与 Java 的互操作性以及对协程的原生支持,使其成为构建现代、高性能服务器端应用的理想选择。
然而,一个强大的语言需要一个同样强大的框架来支撑其在特定领域的应用。在 Java 世界,我们有 Spring、Jakarta EE 等成熟的框架;在 Kotlin 的服务器端生态中,JetBrains 公司为我们带来了官方推荐且量身打造的 Web 框架——Ktor。
Ktor 是一个使用 Kotlin 编写的、用于构建异步应用程序的框架。它专注于构建 Web 应用程序、HTTP 服务、客户端应用程序以及其他需要进行 HTTP 交互的应用程序。与一些“大而全”的框架不同,Ktor 遵循“按需配置”的原则,它的核心非常轻量,通过安装各种特性 (Features) 来添加所需的功能,这使得 Ktor 既灵活又高效。
本篇文章将带领你一步步走进 Ktor 的世界,从它的核心概念讲起,教你如何搭建第一个 Ktor 项目,编写简单的 HTTP 服务,并介绍一些常用的 Ktor 特性,最终让你能够快速上手 Ktor 开发。
第一部分:Ktor 基础概念与核心特性
在深入实践之前,理解 Ktor 的设计哲学和核心概念至关重要。
1. Ktor 的设计哲学:灵活、异步、基于协程
- 灵活 (Flexible): Ktor 的核心功能非常精简,大部分功能(如路由、序列化、身份验证等)都是通过安装“特性”(Features) 来实现的。这种模块化的设计使得开发者可以根据项目需求选择性地添加功能,避免了不必要的开销,保持应用精简高效。
- 异步 (Asynchronous): Ktor 从设计之初就考虑到了异步 I/O。它基于 Kotlin 协程构建,这意味着你可以使用同步风格的代码来编写异步逻辑,极大地提高了开发效率和代码可读性,同时能够更好地处理高并发请求。
- 基于协程 (Coroutine-based): Kotlin 协程是 Ktor 异步能力的核心。它允许你在不阻塞线程的情况下执行挂起操作(如网络请求、数据库访问),从而用少量线程处理大量并发连接,提高了服务器的吞吐量。
2. 核心组件与概念
- Application: Ktor 应用程序的顶级容器。它代表了一个 Ktor Web 应用实例。你在
Application
中配置路由、安装特性等。通常通过embeddedServer
函数或io.ktor.server.netty.EngineMain
入口点启动。 - Engine: Ktor 是一个嵌入式服务器框架,它并不依赖外部的 Tomcat、Jetty 等应用服务器。Ktor 内置了对 Netty、Jetty、Tomcat 等多种 HTTP 引擎的支持。你可以根据需要选择合适的引擎。Netty 是 Ktor 的默认和推荐引擎,因为它与 Ktor 的异步特性结合得最好。
- Module: Ktor 应用程序的功能通常被组织到模块中。一个模块就是一个
Application.() -> Unit
类型的扩展函数。你可以在模块中安装特性、定义路由等。这样做有助于代码的组织和复用。Application.kt
中的module
函数就是一个典型的模块。 - Routing: 路由是 Ktor 中处理不同 URL 请求的核心机制。它将特定的 HTTP 方法和路径映射到相应的代码块(处理函数)。在处理函数中,你可以访问请求信息、执行业务逻辑并发送响应。
- Call:
ApplicationCall
代表了一个独立的客户端请求及其对应的服务器响应。在路由的处理函数中,你可以通过call
对象访问请求(call.request
)并发送响应(call.respond(...)
)。 - Feature (特性/插件): 这是 Ktor 的扩展机制。特性是一些封装好的功能模块,通过
application.install(Feature)
的方式添加到 Application 中。常见的特性包括Routing
,ContentNegotiation
,Authentication
,StaticContent
,CallLogging
等。 - Context (上下文): 在 Ktor 中,很多操作都在特定的上下文中执行,比如
Route
上下文用于定义嵌套路由,ApplicationCall
上下文用于处理请求和响应。
3. Ktor 与其他框架的对比(简要)
- vs Spring/Spring Boot: Spring 是一个非常成熟且功能全面的框架,拥有庞大的生态系统和社区。Spring Boot 简化了 Spring 应用的配置和部署。Spring 也支持响应式编程(WebFlux)。Ktor 更专注于 Web/HTTP 层面,更加轻量和灵活,对 Kotlin 的协程支持原生且深度集成。对于纯 Kotlin 项目或追求极致轻量和灵活的应用,Ktor 是一个不错的选择。Spring 更适合需要大量现有 Spring 生态集成或喜欢约定大于配置模式的项目。
- vs Vert.x: Vert.x 也是一个多语言的、事件驱动的、异步的框架。它基于 Event Loop 模型。Ktor 则基于 Kotlin 协程。两者都是构建高性能异步服务的优秀框架,选择取决于个人偏好和团队对协程或Event Loop模型的熟悉程度。
第二部分:搭建你的第一个 Ktor 项目
开始动手是学习最好的方式。我们将使用 Ktor 官方提供的项目生成器来快速搭建一个项目。
1. 前置准备
在开始之前,请确保你的开发环境具备以下条件:
- JDK: Java Development Kit 8 或更高版本。建议使用 OpenJDK。
- Kotlin: 熟悉 Kotlin 语言的基础语法和概念。对协程有初步了解更佳。
- IDE: IntelliJ IDEA (社区版或旗舰版)。IntelliJ IDEA 提供了对 Kotlin 和 Ktor 的良好支持,尤其是旗舰版有专门的 Ktor 项目向导。如果使用其他 IDE,需要手动配置项目结构。
- 构建工具: Maven 或 Gradle。本文将以 Gradle (Kotlin DSL) 为例,这是 Kotlin 项目中常用的构建工具。
2. 使用 Ktor Project Generator
访问 Ktor 官方的项目生成器网站:start.ktor.io。这个网站类似于 Spring Initializr,可以帮助你快速生成 Ktor 项目的基本骨架。
按照以下步骤操作:
- Name: 输入项目名称,例如
MyFirstKtorApp
。 - Build System: 选择
Gradle (Kotlin)
。这是 Kotlin 项目的推荐选择。 - Engine: 选择
Netty
。这是 Ktor 默认且推荐的异步 I/O 引擎。 - Website / Group / Artifact: 根据你的习惯填写,例如
com.example
为 Group,MyFirstKtorApp
为 Artifact。 - Ktor Version: 选择最新的稳定版本。
- Configuration in: 选择
HOCON
。这是 Ktor 常用的配置文件格式,支持嵌套和结构化配置。 - Add Features: 这是 Ktor 的核心。点击 “Add features” 并搜索或浏览添加以下常用特性:
- Routing: 路由功能,将不同的请求路径映射到处理代码。必选。
- Kotlinx.Serialization: 用于 JSON 等数据格式的序列化和反序列化。非常常用,选择
Content negotiation
并勾选Kotlinx.Serialization
。 - Static Content: 用于提供静态文件服务(如 HTML, CSS, JS, 图片)。对于 Web 应用或需要提供前端资源的后端很有用。
- Call Logging: 记录每个请求的信息,方便调试和监控。
- Default Headers: 自动为响应添加一些默认头信息,如
Server
。 - Status Pages: 定义自定义的错误页面或错误处理逻辑(如处理 404 Not Found)。
- (你可以根据需要添加其他特性,但对于入门,这些已经足够。)
- Generate Project: 点击右下角的 “Generate Project” 按钮,会下载一个 zip 文件。
3. 导入项目到 IntelliJ IDEA
- 解压下载的 zip 文件。
- 打开 IntelliJ IDEA,选择 “Open” 或 “Import Project”。
- 导航到解压后的项目文件夹,选择项目根目录(包含
build.gradle.kts
文件的目录)并打开。 - IntelliJ IDEA 会自动检测这是一个 Gradle 项目,并提示你导入。确认导入并等待 IDEA 同步 Gradle 依赖。这个过程可能需要一些时间,取决于你的网络状况。
4. 项目结构概览
成功导入后,你的项目结构大致如下:
MyFirstKtorApp/
├── .gradle/ (Gradle 缓存目录)
├── .idea/ (IntelliJ IDEA 项目配置)
├── gradle/ (Gradle Wrapper 配置)
│ └── wrapper/
│ └── ...
├── src/
│ ├── main/
│ │ ├── kotlin/
│ │ │ └── com/example/Application.kt (应用程序入口和配置)
│ │ └── resources/
│ │ ├── application.conf (Ktor 配置文件)
│ │ └── static/ (如果添加了 Static Content 特性,会生成)
│ └── test/
│ └── ... (测试代码)
├── build.gradle.kts (Gradle 构建脚本 - Kotlin DSL)
├── gradle.properties (Gradle 属性文件)
├── gradlew (Gradle Wrapper 脚本 - Unix/Linux/macOS)
├── gradlew.bat (Gradle Wrapper 脚本 - Windows)
└── settings.gradle.kts (Gradle 设置脚本)
src/main/kotlin/com/example/Application.kt
: 这是你的应用程序入口点。它包含main
函数用于启动 Ktor 应用程序,以及一个扩展函数module
用于配置 Application。src/main/resources/application.conf
: Ktor 的配置文件,使用 HOCON 格式。你可以在这里配置服务器端口、主机以及特性的参数等。src/main/resources/static/
: 如果你添加了 Static Content 特性,这个目录用于存放需要通过 HTTP 访问的静态文件。build.gradle.kts
: Gradle 构建脚本。在这里声明项目依赖、配置构建任务等。项目生成器已经为你添加了 Ktor 核心、引擎以及你选择的特性的依赖。gradlew
/gradlew.bat
: Gradle Wrapper 脚本,允许你在没有全局安装 Gradle 的情况下运行项目。
第三部分:编写你的第一个 Ktor 服务
现在我们来修改 Application.kt
文件,编写一个简单的 HTTP 服务。
打开 src/main/kotlin/com/example/Application.kt
文件。初始的代码大致如下:
“`kotlin
package com.example
import io.ktor.server.application.
import io.ktor.server.engine.
import io.ktor.server.netty.
import com.example.plugins. // 如果你添加了特性,这里会有导入语句
fun main() {
embeddedServer(Netty, port = 8080, host = “0.0.0.0”, module = Application::module)
.start(wait = true)
}
fun Application.module() {
configureRouting() // 如果你添加了 Routing 特性,会有这个函数调用
configureSerialization() // 如果你添加了 Serialization 特性,会有这个函数调用
configureMonitoring() // 如果你添加了 CallLogging/DefaultHeaders 等,会有这个函数调用
configureStaticContent() // 如果你添加了 Static Content 特性,会有这个函数调用
// … 其他 configureXxx() 函数调用
}
“`
这个结构是 Ktor 应用程序的标准入口。main
函数使用 embeddedServer
启动一个内嵌的 Netty 服务器,监听 8080 端口,主机地址为 0.0.0.0
(允许外部访问),并将 Application::module
函数设置为应用程序的配置模块。module
函数是一个 Application
的扩展函数,里面调用了一系列 configureXxx()
函数。这些 configureXxx()
函数通常是在 plugins
包下由项目生成器为你创建的,用于安装和配置相应的特性。
让我们修改 configureRouting()
函数来定义一些路由。
1. 定义一个简单的 GET 路由
假设 plugins/Routing.kt
文件内容如下(如果没有,手动创建并添加):
“`kotlin
package com.example.plugins
import io.ktor.server.routing.
import io.ktor.server.response.
import io.ktor.server.application.*
fun Application.configureRouting() {
routing {
// 定义一个处理根路径 “/” 的 GET 请求的路由
get(“/”) {
call.respondText(“Hello, Ktor!”)
}
}
}
“`
代码解释:
routing { ... }
: 这是一个构建路由结构的 DSL (Domain Specific Language)。所有路由定义都在这个块内部。get("/") { ... }
: 定义了一个处理 HTTP GET 请求,且请求路径为/
的路由。call.respondText("Hello, Ktor!")
: 这是在路由处理函数中发送响应的方式。call
对象代表当前的请求/响应上下文。respondText()
函数发送一个纯文本响应。
2. 定义一个带路径参数的路由
我们来添加一个路由,可以根据路径中的 ID 获取用户信息(这里只是模拟)。
修改 plugins/Routing.kt
中的 configureRouting
函数:
“`kotlin
package com.example.plugins
import io.ktor.server.routing.
import io.ktor.server.response.
import io.ktor.server.application.
import io.ktor.server.request. // 导入 Request 相关的类
fun Application.configureRouting() {
routing {
get(“/”) {
call.respondText(“Hello, Ktor!”)
}
// 定义一个处理 "/users/{id}" 格式路径的 GET 请求的路由
get("/users/{id}") {
// 从路径参数中获取 "id" 的值
val userId = call.parameters["id"]
if (userId != null) {
call.respondText("Fetching user with ID: $userId")
} else {
// 虽然这里的 {id} 是必需的,但严谨起见,可以处理缺失情况
call.respondText("User ID is missing in the path.", status = io.ktor.http.HttpStatusCode.BadRequest)
}
}
}
}
“`
代码解释:
get("/users/{id}") { ... }
: 定义了一个 GET 路由,路径是/users/
后面跟着一个路径参数,参数名为id
。call.parameters["id"]
: 通过call.parameters
访问路径参数(和查询参数)。它返回一个Parameters
对象,可以通过键(这里是"id"
)获取参数值。返回类型是String?
,因为参数可能不存在(尽管在这个特定的路由定义中id
是必需的)。
3. 定义一个带查询参数的路由
再添加一个搜索路由,通过查询参数获取搜索关键词。
修改 plugins/Routing.kt
中的 configureRouting
函数:
“`kotlin
package com.example.plugins
import io.ktor.server.routing.
import io.ktor.server.response.
import io.ktor.server.application.
import io.ktor.server.request.
fun Application.configureRouting() {
routing {
get(“/”) {
call.respondText(“Hello, Ktor!”)
}
get("/users/{id}") {
val userId = call.parameters["id"]
if (userId != null) {
call.respondText("Fetching user with ID: $userId")
} else {
call.respondText("User ID is missing in the path.", status = io.ktor.http.HttpStatusCode.BadRequest)
}
}
// 定义一个处理 "/search" 路径的 GET 请求的路由
get("/search") {
// 从查询参数中获取 "query" 的值
val searchQuery = call.request.queryParameters["query"]
if (!searchQuery.isNullOrBlank()) {
call.respondText("Searching for: $searchQuery")
} else {
call.respondText("Please provide a 'query' parameter.", status = io.ktor.http.HttpStatusCode.BadRequest)
}
}
}
}
“`
代码解释:
get("/search") { ... }
: 定义了一个 GET 路由,路径是/search
。call.request.queryParameters["query"]
: 通过call.request.queryParameters
访问查询参数。同样,通过键"query"
获取参数值,返回String?
。
4. 使用 Content Negotiation (Serialization) 返回 JSON
如果你在项目生成器中添加了 Content negotiation
并选择了 Kotlinx.Serialization
,那么 plugins
包下应该有一个 Serialization.kt
文件,内容大致如下:
“`kotlin
package com.example.plugins
import io.ktor.serialization.kotlinx.json.
import io.ktor.server.application.
import io.ktor.server.plugins.contentnegotiation.
import io.ktor.server.response.
import io.ktor.server.request.
import io.ktor.server.routing.
import kotlinx.serialization.* // 导入 kotlinx.serialization 注解
fun Application.configureSerialization() {
install(ContentNegotiation) {
json() // 配置 JSON 序列化器,使用 kotlinx.serialization
}
// 可选: 添加一个测试路由来验证序列化
routing {
get("/json/kotlinx") {
call.respond(mapOf("hello" to "world")) // 示例:返回一个 Map,会被序列化为 JSON
}
}
}
“`
代码解释:
install(ContentNegotiation) { json() }
: 这行代码安装了ContentNegotiation
特性,并配置了使用kotlinx.serialization
的 JSON 格式。安装了这个特性后,Ktor 能够根据请求的Accept
头和响应数据的类型,自动进行序列化和反序列化。@Serializable
: 这是kotlinx.serialization
库提供的注解,用于标记可以被序列化/反序列化的数据类。call.respond(data)
: 当你使用respond()
函数而不是respondText()
或respondBytes()
时,Ktor 会查找已安装的ContentNegotiation
特性,尝试将data
对象序列化成合适的格式(这里是 JSON)并发送。
让我们创建一个简单的数据类并用 JSON 格式返回它。
首先,在你的项目中的某个地方(例如 src/main/kotlin/com/example/models/User.kt
)创建数据类:
“`kotlin
package com.example.models
import kotlinx.serialization.Serializable
@Serializable
data class User(val id: String, val name: String)
“`
然后在 plugins/Routing.kt
或 plugins/Serialization.kt
(如果你想把相关路由放在一起)中添加一个新的路由来返回 User
对象:
kotlin
// 在 configureRouting 或 configureSerialization 的 routing 块中添加
get("/users/json/{id}") {
val userId = call.parameters["id"]
if (userId != null) {
// 创建一个 User 对象
val user = User(id = userId, name = "User $userId")
// Ktor 会自动将 user 对象序列化为 JSON
call.respond(user)
} else {
call.respondText("User ID is missing.", status = io.ktor.http.HttpStatusCode.BadRequest)
}
}
现在访问 /users/json/123
应该会返回一个 JSON 响应:{"id":"123","name":"User 123"}
。
5. 提供静态文件服务
如果你在项目生成器中添加了 Static Content
特性,plugins
包下应该有一个 StaticContent.kt
文件,内容大致如下:
“`kotlin
package com.example.plugins
import io.ktor.server.application.
import io.ktor.server.plugins.staticcontent.
import io.ktor.server.routing.*
fun Application.configureStaticContent() {
routing {
// Static plugin. For demo purposes, only serves files from the ‘static’ folder
// install(ContentNegotiation) {
// json()
// }
staticResources(“/static”, “static”) { // 将 “/static” URL 路径映射到 resources 目录下的 “static” 文件夹
precompress(CompressedFileType.GZIP, CompressedFileType.BROTLI) // 启用压缩
default(“index.html”) // 如果访问 “/static/”,默认查找 index.html
}
}
}
“`
代码解释:
staticResources("/static", "static") { ... }
: 这行代码是StaticContent
特性提供的 DSL。它将所有以/static
开头的请求路径映射到项目的src/main/resources/static
目录下的文件。- 第一个参数
"/static"
是 URL 路径前缀。 - 第二个参数
"static"
是资源目录的名称(相对于src/main/resources
)。 precompress
: 启用 GZIP 和 Brotli 压缩,如果客户端支持,服务器会发送预压缩的文件版本(例如index.html.gz
)。default("index.html")
: 当访问/static/
路径时,如果该目录下存在index.html
,则默认返回index.html
。
- 第一个参数
在 src/main/resources/static
目录下创建一个简单的 index.html
文件:
“`html
Hello from Ktor Static!
This page is served as static content by Ktor.
“`
现在,访问 localhost:8080/static/index.html
或 localhost:8080/static/
都应该能看到这个 HTML 页面。
第四部分:运行和测试你的 Ktor 应用
有两种主要方式可以运行 Ktor 应用程序:
1. 从 IntelliJ IDEA 运行
- 打开
src/main/kotlin/com/example/Application.kt
文件。 - 找到
main
函数。 - 在
main
函数旁边的绿色小箭头上点击,选择 “Run ‘ApplicationKt'”。
IntelliJ IDEA 会使用 Gradle 任务编译并运行你的应用程序。你会在 Run 控制台中看到应用程序启动的日志,通常会显示服务器正在监听的端口(默认为 8080)。
2. 使用 Gradle Wrapper 从命令行运行
打开终端或命令行窗口,导航到你的项目根目录。
- 在 Unix/Linux/macOS 上执行:
./gradlew run
- 在 Windows 上执行:
gradlew.bat run
Gradle Wrapper 会下载必要的 Gradle 版本(如果尚未下载),编译你的项目,然后运行 main
函数。
测试
应用程序启动后,你可以使用浏览器或命令行工具(如 curl
)来测试不同的路由:
- 根路径: 在浏览器中访问
http://localhost:8080/
,应该看到 “Hello, Ktor!”。 - 路径参数: 在浏览器中访问
http://localhost:8080/users/42
,应该看到 “Fetching user with ID: 42″。 - 查询参数: 在浏览器中访问
http://localhost:8080/search?query=ktor%20guide
,应该看到 “Searching for: ktor guide”。 - JSON 响应: 在浏览器或使用
curl http://localhost:8080/users/json/99
,应该看到{"id":"99","name":"User 99"}
。 - 静态文件: 在浏览器中访问
http://localhost:8080/static/
或http://localhost:8080/static/index.html
,应该看到index.html
的内容。
按下 Ctrl+C
可以在终端中停止应用程序。
第五部分:Ktor 的其他重要特性(简要介绍)
Ktor 的强大之处在于其丰富的特性生态。除了我们已经使用的路由、序列化和静态内容,还有许多其他重要的特性:
- Authentication (认证): 用于验证客户端的身份。支持多种认证方案,如 Basic, Digest, Form, OAuth, JWT 等。你可以配置不同的区域应用不同的认证策略。
- Authorization (授权): 在认证成功后,检查已认证的用户是否有权限执行某个操作或访问某个资源。通常与认证特性一起使用。
- Sessions: 用于在多次请求之间保持用户状态。支持基于 Cookie 或自定义存储的会话管理。
- WebSockets: 支持构建双向通信的 WebSocket 服务端点。非常适合实时应用。
- Templating: 集成了多种模板引擎(如 FreeMarker, Thymeleaf, Velocity)用于生成动态 HTML 页面。
- Call Logging: 记录请求的详细信息(方法、路径、状态码、响应时间等),非常有助于调试和监控。项目生成器通常会默认安装。
- Default Headers: 自动为所有响应添加一组默认的 HTTP 头。项目生成器通常会默认安装。
- Status Pages: 自定义处理不同 HTTP 状态码的响应,例如为 404 Not Found 或 500 Internal Server Error 提供自定义页面。项目生成器通常会默认安装。
- CORS (Cross-Origin Resource Sharing): 配置跨域资源共享策略,允许来自不同源的浏览器客户端访问你的 API。
- Compression: 启用响应内容的压缩(如 GZIP),减少传输数据量,提高性能。
- HTTP ETag, Last-Modified: 支持 HTTP 缓存相关的头信息,优化客户端缓存。
要使用这些特性,你通常需要在 build.gradle.kts
文件中添加相应的依赖,然后在 Application.module()
函数中或单独的配置函数中调用 install(Feature)
。
第六部分:Ktor 开发进阶方向
恭喜你已经搭建并运行了第一个 Ktor 应用!这只是 Ktor 世界的冰山一角。接下来,你可以根据兴趣和项目需求深入探索以下方向:
- 数据库集成: Ktor 本身不提供数据库访问层,但可以轻松集成各种 Kotlin/Java 的数据库库,如 Exposed (Kotlin SQL 框架), Hibernate, MyBatis 或直接使用 JDBC。你需要在 Ktor 应用中管理数据库连接和事务。
- 异步编程和协程: 深入理解 Kotlin 协程,学习如何更有效地利用协程处理并发和异步任务,避免常见的陷阱。Ktor 的异步特性依赖于协程。
- 测试: Ktor 提供了方便的测试工具,可以使用
withTestApplication
或testApplication
函数模拟 HTTP 请求来测试路由和应用逻辑。学习如何为你的 Ktor 服务编写有效的自动化测试。 - 部署: 学习如何将你的 Ktor 应用程序打包成可执行 JAR 文件或 Docker 镜像,并部署到服务器、云平台(如 Heroku, AWS, GCP, Azure)或容器编排平台(如 Kubernetes)。
- 构建 RESTful API: 学习如何设计和实现符合 RESTful 规范的 API,包括使用不同的 HTTP 方法(GET, POST, PUT, DELETE)、状态码以及如何处理请求体和响应体(特别是 JSON)。
- 构建 Web 应用程序: 如果你要构建传统的 Web 应用(后端渲染 HTML),学习如何使用 Ktor 的模板引擎特性。
- 安全性: 深入学习 Ktor 的认证、授权特性,以及如何处理 HTTPS、防止常见的 Web 安全漏洞(如 XSS, CSRF)。
- 日志和监控: 配置更详细的日志,集成监控系统(如 Prometheus, Grafana)来跟踪应用性能和健康状况。
总结
本文带你快速入门了 Ktor Web 框架。我们了解了 Ktor 的设计哲学,学习了其核心概念,使用官方工具生成了项目骨架,并通过编写简单的路由和使用常用特性(路由、序列化、静态内容)构建了一个基础的 Ktor 应用程序,最后演示了如何运行和测试它。
Ktor 凭借其基于 Kotlin 协程的异步特性、灵活的模块化设计和对 Kotlin 语言的深度集成,成为了构建现代、高性能服务器端应用的一个极具吸引力的选择。希望这篇指南能为你打开 Ktor 开发的大门,鼓励你进一步探索这个充满活力的框架。
现在,是时候开始用 Ktor 构建你自己的 Web 应用和 HTTP 服务了!祝你编码愉快!