Server Applications

预计阅读时间:5分钟

Ktor server introduction and key concepts

目录:

Application and ApplicationEnvironment

ktor应用程序的运行实例由Application类表示. ktor 应用程序由一组模块 (可能是一个模块 )组成. 每个模块都是常规的kotlin lambda或一个函数(通常将应用程序的实例作为接收器或参数).

在具有应用程序配置ApplicationEnvironment表示的环境内部启动应用 程序 (有关更多详细信息,请参见" 配置"页面).

ktor 服务器从环境启动,并控制应用程序生命周期. 应用程序实例是由环境创建和销毁的(取决于实现方式,它可能会延迟创建它或提供热重载功能). 因此,停止应用程序并不总是意味着服务器正在停止:例如,可以在服务器继续运行时重新加载应用程序.

启动应用程序时,应用程序模块将一个一个地启动,并且每个模块都可以配置该应用程序的实例. 通过安装功能部件和拦截管道来配置应用程序实例.

有关更多详细信息,请参见生命周期 .

Features

功能是可以插入到应用程序中的一部分特定功能. 它通常拦截请求和响应并执行其特定功能. 例如, 默认标头功能拦截响应并追加DateServer标头. 可以使用以下install功能install功能安装到应用程序中:

application.install(DefaultHeaders) {
   // configure feature
}

对于某些功能,配置lambda是可选的. 在这种情况下,该功能只能安装一次. 但是,在某些情况下需要配置组成. 对于此类功能,有些帮助程序功能会在尚未安装功能的情况下安装该功能并应用配置lambda. 例如, routing {} .

Calls and pipelines

在ktor中,一对传入的请求和响应(完整或不完整)被称为ApplicationCall . 每个应用程序调用都通过由几个(或没有) 拦截器组成的ApplicationCallPipeline传递. 拦截器由一个被调用的一个和每一个拦截器可以修改通过程序的请求或响应和控制流水线执行( proceed()到下一拦截或精加工( finish()finishAll()的整个流水线执行(从而下一个拦截不会被调用,有关详细信息,请参见PipelineContext . 它还可以装饰其余的拦截器链,在proceed()调用之前和之后proceed()其他操作.

考虑以下装饰示例:

intercept {
    myPrepare()
    try {
        proceed()
    } finally {
        myComplete()
    }
}

管道可能包含多个阶段 . 每个拦截器都在特定阶段注册. 因此,拦截器按其阶段顺序执行. 有关更详细的说明,请参见管道文档.

Application call

应用程序调用由一对带有响应的请求和一组参数组成. 因此,应用程序调用管道具有一对接收发送管道. 可以使用ApplicationCall.receive<T>()接收请求的内容(正文),其中T是期望的内容类型. 例如, call.receive<String>()将请求主体读取为String . 某些类型的收件箱可以直接使用,而无需其他配置,而接收自定义类型的包可能需要功能安装或配置. 每个receive()都会使接收管道( ApplicationCallPipeline.receivePipeline )从头开始执行,因此每个接收管道拦截器都可以转换或绕过请求主体. 原始主体对象类型为ByteReadChannel (异步字节通道).

可以通过执行响应管道的ApplicationCall.respond(Any)函数调用( ApplicationCallPipeline.respondPipeline )来提供应用程序响应主体. 与接收管道类似,每个响应管道拦截器都可以转换响应对象. 最后,应将响应对象转换为OutgoingContent的实例.

一组扩展函数respondTextrespondBytesreceiveTextreceiveParameters等简化请求和响应对象的构造.

Routing

空的应用程序没有拦截器,因此将为每个请求生成404 Not Found. 应拦截应用程序调用管道以处理请求. 拦截器可以根据请求URI进行响应,如下所示:

intercept {
    val uri = call.request.uri
    when {
        uri == "/" -> call.respondText("Hello, World!")
        uri.startsWith("/profile/") -> { TODO("...") }
    }
}

当然,这种方法有很多缺点. 幸运的是,存在用于结构化请求处理的路由功能,该功能可拦截应用程序调用管道,并提供一种注册路由处理程序的方法. 由于路由唯一要做的就是拦截应用程序调用管道,因此使用路由进行手动拦截也可以. 路由由具有处理程序和拦截器的路由树组成. ktor中的一组扩展函数提供了一种注册处理程序的简单方法,如下所示:

routing {
    get("/") {
        call.respondText("Hello, World!")
    }
    get("/profile/{id}") { TODO("...") }
}

Notice that routes are organized into a tree so you can declare structured routes:

routing {
    route("profile/{id}") {
        get("view") { TODO("...") }
        get("settings") { TODO("...") }
    }
}

路由路径可以包含常量部分和参数,例如上例中的{id} . 使用属性call.parameters可以访问捕获的设置值.

Content Negotiation

ContentNegotiation提供了一种协商哑剧类型并使用AcceptContent-Type标头转换类型的方法. 可以为特定的内容类型注册内容转换器,以接收和响应对象. 开箱即用有JacksonGsonkotlinx.serialization内容转换器,可以将其插入功能.

Example:

install(ContentNegotiation) {
    gson {
        // Configure Gson here
    }
}
routing {
    get("/") {
        call.respond(MyData("Hello, World!"))
    }
}

What’s next

by  ICOPY.SITE