Ktor 是一个用于 Kotlin 的异步 HTTP 客户端,由 JetBrains 公司开发,是同名框架的一部分,用于服务器端和客户端开发。Ktor 基于 Kotlin 协程构建,并支持多平台。根据 JetBrains, 2025 的数据,Ktor 无需反射和额外依赖即可与 Kotlin 生态系统进行原生集成。
要点
Ktor 是一个用 Kotlin 构建异步服务器和客户端应用程序的框架,由 JetBrains 创建。Ktor Client 是该框架的客户端部分,提供完全支持 Kotlin 协程、多平台(JVM、Native、JS)和基于插件的模块化架构的 HTTP 客户端。
Ktor 于 2018 年出现,作为 Kotlin-first 项目中 Retrofit 和 OkHttp 的替代方案。与移植了 Java 注解方法的 Retrofit 不同,Ktor Client 使用 Kotlin DSL 来配置请求——无需注解和反射。这使得代码对 Kotlin 开发者来说更易读且类型安全。
根据 Kotlin Multiplatform 2024 调查,Ktor Client 在 35% 的 Kotlin Multiplatform Mobile (KMM) 项目中使用,使其成为 Kotlin 社区中仅次于 OkHttp 的第二大流行 HTTP 客户端。在多平台和与 Kotlin 生态系统原生集成重要的项目中,Ktor 更受青睐。
Ktor Client 架构 基于插件管道(pipeline)。每个请求通过已安装插件的序列,这些插件可以修改请求、响应或执行附加操作——日志记录、压缩、序列化、身份验证。
通过 HttpClient { } DSL 块创建 HTTP 客户端时,您指定引擎(OkHttp、Android、CIO、Darwin)并安装插件。每个引擎为特定平台实现低级别的请求发送:在 Android 上使用 OkHttp 引擎,在 iOS 上使用 Darwin(URLSession),在 Desktop 上使用 CIO(基于协程的 I/O)。HttpClient 自动为当前平台选择最佳引擎。
Ktor Client 中的请求通过 suspend 函数执行,这意味着与协程完全集成。无需 Callback、RxJava 或 LiveData——只有使用 suspend 的顺序代码,异步工作而不阻塞线程。
Ktor 管道 由多个阶段组成:首先请求通过已安装的插件(例如,用于 JSON 的 ContentNegotiation,用于日志的 Logging),然后引擎执行 HTTP 请求,响应再次通过插件进行反序列化。每个插件是在管道协程中执行的 suspend 函数。
Ktor 管道的一个重要优势是 条件处理 的可能性。插件可以检查请求的 URL 或标头,如果条件不满足则跳过处理。例如,使用 gzip 的 ContentEncoding 仅应用于包含 Content-Encoding: gzip 标头的响应,而 Auth 仅对受保护的端点生效,不影响公共 API。
这种管道方法允许 灵活组合插件:您可以安装带 JSON 的 ContentNegotiation,添加带 Bearer 令牌的 Auth,启用 ContentEncoding 压缩和 HttpTimeout——它们全部按正确顺序协同工作。插件的安装顺序很重要:首先安装的插件将比其他插件更早处理请求。
插件 是 Ktor 的模块化扩展系统,取代了 Retrofit 注解和 OkHttp 拦截器。每个插件解决特定任务,并通过 HttpClient 块中的 install() 函数安装。Ktor 提供内置插件,也允许创建自定义插件。
| 插件 | 用途 |
|---|---|
| ContentNegotiation | 通过 Kotlinx Serialization 进行 JSON、XML 的序列化和反序列化 |
| Logging | 记录请求和响应,可配置级别 |
| Auth | 身份验证:Basic、Bearer、Digest,支持自动令牌刷新 |
| HttpTimeout | 配置连接、读取和请求的超时时间 |
| ContentEncoding | 透明的 gzip 和 deflate 压缩 |
| DefaultRequest | 为所有请求设置默认值 |
对于特定任务,通过 createClientPlugin 创建自定义 插件。插件可以拦截请求(onRequest)、响应(onResponse)或处理错误(onError)。这完全取代了 OkHttp 中的 Interceptor,但带有类型化的 Kotlin API 和 suspend 函数支持。
自定义插件适用于添加指标、自动重试逻辑、请求跟踪或端点的 A/B 测试。与 OkHttp 拦截器不同,Ktor 插件使用 Kotlin 编写并在协程上下文中工作,简化了错误和超时处理。
用于调试请求的 Logging 插件,支持 ALL、HEADERS 或 BODY 级别。Logging 显示方法、URL、状态、标头以及请求和响应的正文。与 OkHttp 的 HttpLoggingInterceptor 不同,Ktor Logging 异步工作,并可配置为按日志级别(ERROR、WARN、INFO、DEBUG)过滤,无需停止应用程序即可更改配置。
让我们来看一个通过 Ktor Client 的 基本 GET 请求。创建一个安装了 ContentNegotiation 插件用于 JSON 的 HttpClient。请求通过 suspend 函数 get() 执行,结果自动反序列化为 data class。
data class User(
val login: String,
val id: Int,
val avatarUrl: String
)
val client = HttpClient {
install(ContentNegotiation) {
json(Json {
ignoreUnknownKeys = true
})
}
}
suspend fun getUser(): User {
return client.get("https://api.github.com/users/octocat").body()
}
对于 带正文的 POST 请求,使用带 contentType() 和 body() 的 post() 函数。Ktor 通过已安装的 ContentNegotiation 自动将对象序列化为 JSON。DSL 风格使代码顺序且易读。
data class CreateRepo(
val name: String,
val description: String,
val private: Boolean
)
suspend fun createRepo(): Unit {
val repo = CreateRepo(
name = "my-project",
description = "Sample project",
private = false
)
client.post("https://api.github.com/user/repos") {
contentType(ContentType.Application.Json)
setBody(repo)
}
}
HttpTimeout 和 DefaultRequest 是用于配置的两个关键插件。HttpTimeout 设置时间限制,而 DefaultRequest 为所有请求指定标头和 URL 参数,避免在每个调用中重复代码。
val client = HttpClient {
install(HttpTimeout) {
connectTimeoutMillis = 15000
requestTimeoutMillis = 30000
}
install(DefaultRequest) {
url("https://api.github.com/")
header("Accept", "application/json")
}
}
多平台 是 Ktor 相对于 OkHttp 和 Retrofit 的主要优势。Ktor Client 可在 JVM(Android、Server)、Native(iOS、macOS、Windows、Linux)和 JS(Browser)上运行。相同的 HTTP 客户端代码可在所有平台上运行而无需修改,这对于 Kotlin Multiplatform 项目尤为宝贵。
对于每个平台,Ktor 使用自己的引擎。在 Android 上默认应用 OkHttp 引擎,提供与 OkHttp 生态系统的完全兼容性。在 iOS 上使用基于 URLSession 的 DarwinEngine。对于 Server 使用 CIOEngine(基于协程的 I/O)。引擎可以显式指定:HttpClient(OkHttp) { } 或 HttpClient(Darwin) { }。
选择引擎时考虑其能力:OkHttp 引擎支持 HTTP/2 和连接池,DarwinEngine——与 iOS 网络的原生集成和 URLSession 后台会话,CIOEngine——无外部依赖的纯协程实现。对于 Web 目标,使用通过 fetch API 工作的 JsEngine 或 BrowserEngine。
由于所有平台上统一的 API,数据加载代码在 Android、iOS 和 Desktop 上看起来相同。这比在 Retrofit(Android)和 URLSession(iOS)上分别实现相比,可将 KMM 项目中的代码重复减少 60–80%。插件也在所有平台上无需修改即可工作。
忽略关闭 HttpClient 是 Ktor 中的常见错误。HttpClient 实现了 Closeable 接口,在应用程序结束时必须通过 client.close() 关闭。在 Android 中,这是在 Activity 的 onDestroy() 或 ViewModel.onCleared() 中完成的。未关闭的客户端会导致协程和引擎线程泄漏。
插件顺序错误 可能会破坏请求处理。例如,ContentNegotiation 应在 DefaultRequest 之前安装,以便正确应用内容类型。建议将 Logging 安装为最后一个,以便在所有修改后记录请求的最终版本。如果插件行为异常,请尝试调整顺序。
suspend 函数中缺少异常处理。Ktor 在网络错误时抛出 IOException,在 HTTP 4xx 状态时抛出 ClientRequestException。每个 get()、post() 和其他方法调用都必须使用 try-catch 块。在 HttpClient 块中使用 HttpResponseValidator 进行全局错误处理,避免在每个方法中重复 try-catch。
常见问题
Ktor 使用 Kotlin DSL 和插件,无需注解和反射。Retrofit 基于 Java 注解和反射构建。Ktor 支持多平台,Retrofit 仅支持 JVM/Android。Ktor 原生与协程一起工作,Retrofit 通过包装器添加了 suspend。
对于 Android,OkHttp 引擎 是最佳的——提供与 OkHttp 生态系统的兼容性、连接池、缓存和 HTTP/2。通过 HttpClient(OkHttp) { } 选择它。替代方案是 Ktor 内置的 CIOEngine,但在 Android 上稳定性较差。
是的,Ktor 通过相应引擎支持 HTTP/2。OkHttp 引擎从 OkHttp 继承 HTTP/2 支持。iOS 上的 DarwinEngine 通过 URLSession 支持 HTTP/2。CIOEngine 在服务器端支持 HTTP/2。引擎的选择决定了协议支持级别。
使用 Auth 插件并设置 bearer { }。插件自动向每个请求添加 Authorization 标头,并可以在 401 响应时通过 refreshTokens 刷新令牌。示例:install(Auth) { bearer { loadTokens { BearerTokens(token, refreshToken) } } }。
是的,Ktor Client 通过使用 URLSession 的 DarwinEngine 在 iOS 上完全工作。所有插件、序列化和协程在 iOS 上的工作方式与 Android 相同。这使得 Ktor 成为 Kotlin Multiplatform Mobile (KMM) 项目的主要 HTTP 客户端。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。