kotlin学习之ktor(2.3.6)-ApplicationCall

ApplicationCall 简介

当处理路由或直接拦截管道时,将获得ApplicationCall的上下文。 ApplicationCall提供对两个主要属性ApplicationRequest和ApplicationResponse的访问。对应于传入的请求和传出的响应。 除此之外,它还提供了一个应用程序环境和一些有用的功能来帮助响应客户端请求。鉴于管道可以异步执行,ApplicationCall还表示带有属性的逻辑执行上下文,以在管道的各个部分之间传递数据。 将拦截器安装到管道中是改变ApplicationCall处理的主要方法。几乎所有Ktor功能都是拦截器,在应用程序调用处理的不同阶段执行各种操作。

intercept(ApplicationCallPipeline.Call) { 
    if (call.request.uri == "/")
        call.respondText("Test String")
}

上述代码将拦截器安装到ApplicationCall处理的呼叫阶段,并在请求根页面时以纯文本响应。

这只是一个例子,通常,页面请求不会以这种方式处理,因为有一个路由机制可以做到这一点,还有更多。此外,如前所述,定义拦截器通常使用具有安装功能的功能完成。 ApplicationCall上可用的大多数函数(如上面的响应文本)都是暂停函数,表明它们可能会异步执行。

处理HTTP请求

在处理路由或直接拦截管道时,您可以使用ApplicationCall获得上下文。该调用包含一个名为request的属性,该属性包含有关请求的信息。 此外,调用本身具有一些有用的便利属性和方法,这些属性和方法依赖于请求。

介绍

当使用路由功能或拦截请求时,可以访问 call 内部的调用属性。该调用包括一个带有 request 相关信息的请求属性:

routing {
    get("/") {
        val uri = call.request.uri
        call.respondText("Request uri: $uri")
    } 
}

intercept(ApplicationCallPipeline.Call) { 
    if (call.request.uri == "/") {
        call.respondText("Test String")
    }
}

Request 信息

作为request的一部分,您可以访问其内部上下文:

URL, method, scheme, protocol, host, path, httpVersion, remoteHost, clientIp

val version: String = request.httpVersion // "HTTP/1.1"
val httpMethod: HttpMethod = request.httpMethod // GET, POST... 
val uri: String = request.uri // Short cut for `origin.uri`
val scheme: String = request.origin.scheme // "http" or "https"
val host: String? = request.host() // The host part without the port 
val port: Int = request.port() // Port of request
val path: String = request.path() // The uri without the query string
val document: String = request.document() // The last component after '/' of the uri
val remoteHost: String = request.origin.remoteHost // The IP address of the client doing the request

反向代理支持:源和本地(origin and local)

当在反向代理(例如nginx或负载均衡器)后面时,接收到的请求不是由最终用户执行的,而是由该反向代理执行的。 这意味着连接的客户端IP地址将是代理的IP地址,而不是客户端的IP地址。 此外,反向代理可能通过HTTPS提供服务,并通过HTTP向服务器请求。流行的反向代理发送X-Forwarded-头, 以便能够访问这些信息。

请注意,为了在反向代理下工作,您必须安装XForwardedHeaderSupport功能。

处理 GET / Query parameters

如果需要访问查询参数?param1=value&param2=value作为一个集合,您可以使用queryParameters。 它实现了StringValues接口,其中每个键都可以有一个与其关联的字符串列表。

val queryParameters: Parameters = request.queryParameters
val param1: String? = request.queryParameters["param1"] // To access a single parameter (first one if repeated)
val repeatedParam: List<String>? = request.queryParameters.getAll("repeatedParam") // Multiple values

您还可以访问原始queryString (param1=value&param2=value)

val queryString: String = request.queryString()

处理 POST PUT PATCH

所有的接收方法都会消耗客户端发送的全部有效负载,因此尝试两次接收请求正文将导致RequestAlreadyConsumedException错误, 除非您安装了DoubleReceive功能。install(DoubleReceive)

接收类型化对象、内容类型和JSON

该调用还支持接收通用对象:

val obj: T = call.receive<T>()
val obj: T? = call.receiveOrNull<T>()

为了从负载中接收自定义对象,您必须使用ContentNegotiation功能。例如,这对于在RESTAPI中接收和发送JSON有效载荷非常有用。

这里需要注意导入gson时要注意ktor版本大于2.0和之前的不同,这里是迁移注意事项

  1. 使用gson
implementation("io.ktor:ktor-server-content-negotiation:$ktor_version")
implementation("io.ktor:ktor-serialization-gson:$ktor_version")

import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.serialization.gson.*
install(ContentNegotiation) {
    gson {
        setDateFormat(DateFormat.LONG)
        setPrettyPrinting()
    }
}
  1. 使用json
implementation("io.ktor:ktor-server-content-negotiation:$ktor_version")

import io.ktor.serialization.kotlinx.json.*
import io.ktor.server.plugins.contentnegotiation.*
install(ContentNegotiation) {
    json()
}