ktor框架用到了netty吗_如何使用 Ktor 快速开发 Web 项目
一. Ktor 介紹
Ktor 是一個高性能的、基于 Kotlin 的 Web 開發框架,支持 Kotlin Coroutines、DSL 等特性。
Ktor 是一個由 Kotlin 團隊打造的 Web 框架,可用于創建異步、高性能和輕量級的 Web 服務器,并使用 Kotlin 慣用的 API 構建非阻塞的多平臺 Web 客戶端。
Ktor 的服務端僅限于 JVM,但是 Ktor 的客戶端是一個 Multiplatform 的庫。
如果使用 Kotlin Multiplatform 構建跨平臺項目時,使用 Ktor 的客戶端作為 Http 框架是一個不錯的選擇。
Ktor 由兩部分組成:服務器引擎和靈活的異步 HTTP 客戶端。當前版本主要集中在 HTTP 客戶端上。客戶端是一個支持 JVM,JS,Android 和 iOS 的多平臺庫,現在經常在跨平臺移動應用程序中使用。
二. Ktor 服務端的使用
我們可以通過多種方式運行 Ktor 服務端程序:
在 main() 中調用 embeddedServer 來啟動 Ktor 應用
運行一個 EngineMain 的 main() 并使用 HOCON application.conf 配置文件
作為 Web 服務器中的 Servlet
在測試中使用 withTestApplication 來啟動 Ktor 應用
2.1 Gradle 配置 Ktor
Kotlin 的版本需要 1.3.x,因為 Ktor 底層會依賴到 Kotlin Coroutines。
在需要使用 Ktor 的 module 中添加如下的依賴:
dependencies {
...
implementation "io.ktor:ktor-server-core:${libs.ktor}"
implementation "io.ktor:ktor-server-netty:${libs.ktor}"
}
復制代碼
后面的例子還會介紹 Ktor 其他的 artifact,例如:freemarker、gson 等。
2.2 embeddedServer
當使用 embeddedServer 時,Ktor 使用 DSL 來配置應用程序和服務器引擎。目前,Ktor 支持 Netty、Jetty、Tomcat、CIO(Coroutine I/O) 作為服務器引擎。(當然,也支持創建自己的引擎并為其提供自定義配置。)
以 Netty 作為服務器引擎為例,通過 embeddedServer 啟動 Ktor 應用:
fun main() {
embeddedServer(Netty, port?:8080, watchPaths = listOf("MainKt"), module = Application::module).start()
}
復制代碼
2.3 ApplicationCall && Routing
當一個請求進入 Ktor 應用時(可以是 HTTP,HTTP / 2 或 WebSocket 請求),該請求將被轉換為 ApplicationCall 并通過該應用程序擁有的管道。Ktor 的管道是由一個或多個預先安裝的攔截器組成,這些攔截器提供某些功能,例如:路由,壓縮等,最終將處理請求。
ApplicationCall 提供對兩個主要屬性 ApplicationRequest 和 ApplicationResponse 的訪問。它們對應于傳入請求和傳出響應。 除了這些之外,ApplicationCall 還提供了一個 ApplicationEnvironment 和一些有用的功能來幫助響應客戶端請求。
Routing 是一項安裝在應用程序中的功能,用于簡化和構建頁面請求處理。Ktor 的 Routing 支持 Restful 的各種方法,以及使用 DSL 進行配置。
Routing 支持嵌套,被稱為 Routing Tree,可以通過遞歸匹配復雜的規則和處理請求。
2.4 CORS
默認情況下,Ktor 提供攔截器以實現對跨域資源共享(CORS)的適當支持。
首先,將 CORS 功能安裝到應用中。
fun Application.main() {
...
install(CORS)
...
}
復制代碼
Ktor CORS 功能的默認配置僅處理 GET,POST 和 HEAD HTTP 方法以及以下標頭:
HttpHeaders.Accept
HttpHeaders.AcceptLanguages
HttpHeaders.ContentLanguage
HttpHeaders.ContentType
復制代碼
下面的例子展示了如何配置 CORS 功能
fun Application.main() {
...
install(CORS)
{
method(HttpMethod.Options)
header(HttpHeaders.XForwardedProto)
anyHost()
host("my-host")
// host("my-host:80")
// host("my-host", subDomains = listOf("www"))
// host("my-host", schemes = listOf("http", "https"))
allowCredentials = true
allowNonSimpleContentTypes = true
maxAge = Duration.ofDays(1)
}
...
}
復制代碼
2.5 Packing
部署 Ktor 應用時,可以使用 fat jar 或者 war 包。
我們以 fat jar 為例,使用 gradle 的 shadow 插件可以方便地打包 Ktor 的應用。
在項目根目錄下的 build.gradle 中添加 shadow 插件的依賴:
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:5.2.0'
......
}
}
復制代碼
然后在需要打包的 module 中添加 shadow 插件和輸出 jar 包名稱以及 jar 包的入口 Main 函數:
plugins {
id 'java'
id 'kotlin'
id 'com.github.johnrengelman.shadow'
}
......
shadowJar {
baseName = 'xxx' // jar 包名稱
manifest {
attributes["Main-Class"] = "xxx.xxx.xxx.xxx" // jar 包的主函數
}
}
復制代碼
三. 例子
以 RxCache 為例,本文會介紹使用 Ktor 開發一個 Local Cache 的 browser(瀏覽器),用于讀取磁盤緩存中的數據。
RxCache 是一款支持 Java 和 Android 的 Local Cache 。目前支持內存、堆外內存、磁盤緩存。
開發的背景:我們存在一些桌面程序部署在 Ubuntu 上,并需要對這些程序進行埋點,而 RxCache 本身支持磁盤的緩存。因此,我使用 RxCache 存儲埋點的數據,所以需要一個瀏覽器的程序來查看本地的埋點數據。
3.1 RxCache 的配置
RxCache 是一個單例,使用時需要先調用 config() 配置 RxCache。
RxCache 支持二級緩存:Memory、Persistence,并擁有多種序列化方式。這些可以通過配置來體現。
val rxCache: RxCache by lazy {
val converter: Converter = when (Config.converter) {
"gson" -> GsonConverter()。
"fastjson" -> FastJSONConverter()
"moshi" -> MoshiConverter()
"kryo" -> KryoConverter()
"hessian" -> HessianConverter()
"fst" -> FSTConverter()
"protobuf" -> ProtobufConverter()
else -> GsonConverter()
}
RxCache.config {
RxCache.Builder().persistence {
when (Config.type) {
"disk" -> {
val cacheDirectory = File(Config.path) // rxCache 持久層存放地址
if (!cacheDirectory.exists()) {
cacheDirectory.mkdir()
}
DiskImpl(cacheDirectory, converter)
}
"okio" -> {
val cacheDirectory = File(Config.path) // rxCache 持久層存放地址
if (!cacheDirectory.exists()) {
cacheDirectory.mkdir()
}
OkioImpl(cacheDirectory, converter)
}
"mapdb" -> {
val cacheDirectory = File(Config.path) // rxCache 持久層存放地址
MapDBImpl(cacheDirectory, converter)
}
"diskmap"-> {
val cacheDirectory = File(Config.path) // rxCache 持久層存放地址
DiskMapImpl(cacheDirectory, converter)
}
else -> {
val cacheDirectory = File(Config.path) // rxCache 持久層存放地址
if (!cacheDirectory.exists()) {
cacheDirectory.mkdir()
}
DiskImpl(cacheDirectory, converter)
}
}
}
}
RxCache.getRxCache()
}
復制代碼
3.2 module
Ktor module 是一個開發者定義的函數,它用于接收 Application 類(該類負責配置服務器管道,安裝功能,注冊路由,處理請求等)。
在本例子中,安裝了 DefaultHeaders、CallLogging、FreeMarker、ContentNegotiation、Routing。
fun Application.module() {
install(DefaultHeaders)
install(CallLogging)
install(FreeMarker) {
templateLoader = ClassTemplateLoader(this::class.java.classLoader, "templates")
defaultEncoding = "utf-8"
}
install(ContentNegotiation) {
gson {
setDateFormat(DateFormat.LONG)
setPrettyPrinting()
}
}
install(Routing) {
......
}
}
復制代碼
3.3 Routing
Routing 提供了對外的頁面。
install(Routing) {
static("/") {
defaultResource("index.html", "web")
}
post("/saveConfig") {
val postParameters: Parameters = call.receiveParameters()
Config.path = postParameters["path"] ?: ""
Config.type = postParameters["type"] ?: ""
Config.converter = postParameters["converter"] ?: ""
call.respond(FreeMarkerContent("save.ftl", mapOf("config" to Config)))
}
get("/list") {
val file = File(Config.path)
val array = file.list()
call.respond(array)
}
get("/detail/{key}") {
val key = call.parameters["key"]
val json = rxCache.getStringData(key)
call.respondText(json)
}
get("/info") {
val json = rxCache.info
call.respondText(json)
}
}
復制代碼
其中 index.html 用于配置 RxCache。
saveConfig 用于展示保存的 RxCache 的數據,其中用到了 FreeMarker 的模板 save.ftl
Hi
RxCache's path: ${config.path}
RxCache's persistence: ${config.type}
RxCache's serialization: ${config.converter}
復制代碼
list 接口、detail 接口分別用于展示磁盤存儲數據的 key,以及根據 key 來查詢詳細的存儲內容。
info 接口用于顯示緩存中的信息。
3.4 啟動
browser 配置了 kotlinx-cli,它可以通過命令行解析參數。目前,只支持 '-p' 用于表示啟動 Ktor 應用的端口號。
browser 使用 Netty 作為服務器引擎。
fun main(args: Array) {
val parser = ArgParser("rxcache-browser")
val port by parser.option(ArgType.Int, shortName = "p", description = "Port number of the local web service")
parser.parse(args)
embeddedServer(Netty, port?:8080, watchPaths = listOf("MainKt"), module = Application::module).start()
}
復制代碼
四. 小結
Ktor 構建的應用,只需少量代碼和配置即可完成,非常簡便。
非常適用于簡單的 Web 項目、對外提供接口的 OpenAPI 項目。當然使用它來構建微服務也是可以,它也有豐富的 Features。
總結
以上是生活随笔為你收集整理的ktor框架用到了netty吗_如何使用 Ktor 快速开发 Web 项目的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql关联查询去重_MySQL外键和
- 下一篇: 排队问题解题思路_三大策略、5个技巧,完