如何使用 Ktor 快速开发 Web 项目

简介: 如何使用 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 服务端程序:

image.png

Ktor Server.png


  • 在 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

<html>
<h2>Hi</h2>
RxCache's path: ${config.path} </br>
RxCache's persistence: ${config.type} </br>
RxCache's serialization: ${config.converter} </br>
</html>


list 接口、detail 接口分别用于展示磁盘存储数据的 key,以及根据 key 来查询详细的存储内容。


image.png

list 接口


image.png

detail 接口


info 接口用于显示缓存中的信息。


image.png

info 接口


3.4 启动


browser 配置了 kotlinx-cli,它可以通过命令行解析参数。目前,只支持 '-p' 用于表示启动 Ktor 应用的端口号。


browser 使用 Netty 作为服务器引擎。

fun main(args: Array<String>) {
    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

相关文章
|
2月前
|
算法 Java Go
【GoGin】(1)上手Go Gin 基于Go语言开发的Web框架,本文介绍了各种路由的配置信息;包含各场景下请求参数的基本传入接收
gin 框架中采用的路优酷是基于httprouter做的是一个高性能的 HTTP 请求路由器,适用于 Go 语言。它的设计目标是提供高效的路由匹配和低内存占用,特别适合需要高性能和简单路由的应用场景。
271 4
|
3月前
|
安全 Java API
Java Web 在线商城项目最新技术实操指南帮助开发者高效完成商城项目开发
本项目基于Spring Boot 3.2与Vue 3构建现代化在线商城,涵盖技术选型、核心功能实现、安全控制与容器化部署,助开发者掌握最新Java Web全栈开发实践。
413 1
|
6月前
|
缓存 JavaScript 前端开发
鸿蒙5开发宝藏案例分享---Web开发优化案例分享
本文深入解读鸿蒙官方文档中的 `ArkWeb` 性能优化技巧,从预启动进程到预渲染,涵盖预下载、预连接、预取POST等八大优化策略。通过代码示例详解如何提升Web页面加载速度,助你打造流畅的HarmonyOS应用体验。内容实用,按需选用,让H5页面快到飞起!
|
6月前
|
JavaScript 前端开发 API
鸿蒙5开发宝藏案例分享---Web加载时延优化解析
本文深入解析了鸿蒙开发中Web加载完成时延的优化技巧,结合官方案例与实际代码,助你提升性能。核心内容包括:使用DevEco Profiler和DevTools定位瓶颈、四大优化方向(资源合并、接口预取、图片懒加载、任务拆解)及高频手段总结。同时提供性能优化黄金准则,如首屏资源控制在300KB内、关键接口响应≤200ms等,帮助开发者实现丝般流畅体验。
|
前端开发 JavaScript Shell
鸿蒙5开发宝藏案例分享---Web页面内点击响应时延分析
本文为鸿蒙开发者整理了Web性能优化的实战案例解析,结合官方文档深度扩展。内容涵盖点击响应时延核心指标(≤100ms)、性能分析工具链(如DevTools时间线、ArkUI Trace抓取)以及高频优化场景,包括递归函数优化、网络请求阻塞解决方案和setTimeout滥用问题等。同时提供进阶技巧,如首帧加速、透明动画陷阱规避及Web组件初始化加速,并通过优化前后Trace对比展示成果。最后总结了快速定位问题的方法与开发建议,助力开发者提升Web应用性能。
|
4月前
|
JavaScript Java 微服务
现代化 Java Web 在线商城项目技术方案与实战开发流程及核心功能实现详解
本项目基于Spring Boot 3与Vue 3构建现代化在线商城系统,采用微服务架构,整合Spring Cloud、Redis、MySQL等技术,涵盖用户认证、商品管理、购物车功能,并支持Docker容器化部署与Kubernetes编排。提供完整CI/CD流程,助力高效开发与扩展。
551 64
|
6月前
|
JSON 开发框架 自然语言处理
【HarmonyOS Next之旅】基于ArkTS开发(三) -> 兼容JS的类Web开发(三)
本文主要介绍了应用开发中的三大核心内容:生命周期管理、资源限定与访问以及多语言支持。在生命周期部分,详细说明了应用和页面的生命周期函数及其触发时机,帮助开发者更好地掌控应用状态变化。资源限定与访问章节,则聚焦于资源限定词的定义、命名规则及匹配逻辑,并阐述了如何通过 `$r` 引用 JS 模块内的资源。最后,多语言支持部分讲解了如何通过 JSON 文件定义多语言资源,使用 `$t` 和 `$tc` 方法实现简单格式化与单复数格式化,为全球化应用提供便利。
265 104
|
6月前
|
JavaScript 前端开发 API
【HarmonyOS Next之旅】基于ArkTS开发(三) -> 兼容JS的类Web开发(二)
本文介绍了HarmonyOS应用开发中的HML、CSS和JS语法。HML作为标记语言,支持数据绑定、事件处理、列表渲染等功能;CSS用于样式定义,涵盖尺寸单位、样式导入、选择器及伪类等特性;JS实现业务逻辑,包括ES6语法支持、对象属性、数据方法及事件处理。通过具体代码示例,详细解析了页面构建与交互的实现方式,为开发者提供全面的技术指导。
286 104
|
6月前
|
开发框架 编解码 JavaScript
【HarmonyOS Next之旅】基于ArkTS开发(三) -> 兼容JS的类Web开发(一)
该文档详细介绍了一个兼容JS的类Web开发范式的方舟开发框架,涵盖概述、文件组织、js标签配置及app.js等内容。框架采用HML、CSS、JavaScript三段式开发方式,支持单向数据绑定,适合中小型应用开发。文件组织部分说明了目录结构、访问规则和媒体文件格式;js标签配置包括实例名称、页面路由和窗口样式信息;app.js则描述了应用生命周期与对象管理。整体内容旨在帮助开发者快速构建基于方舟框架的应用程序。
288 102
|
5月前
|
安全 JavaScript Java
java Web 项目完整案例实操指南包含从搭建到部署的详细步骤及热门长尾关键词解析的实操指南
本项目为一个完整的JavaWeb应用案例,采用Spring Boot 3、Vue 3、MySQL、Redis等最新技术栈,涵盖前后端分离架构设计、RESTful API开发、JWT安全认证、Docker容器化部署等内容,适合掌握企业级Web项目全流程开发与部署。
396 0

热门文章

最新文章