Handling HTTP Requests

预计阅读时间:6分钟

在处理路由或直接拦截管道时,您将获得一个带有ApplicationCall的上下文. 该call包含一个名为request的属性,该属性包含有关该请求的信息.

此外,调用本身具有一些有用的便利属性和依赖于请求的方法.

目录:

Introduction

使用" 路由"功能或拦截请求时,可以访问处理程序中的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 information

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

val call: ApplicationCall = request.call
val pipeline: ApplicationReceivePipeline = request.pipeline

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

Reverse proxy support: origin and local

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

请注意,要在反向代理下实现此功能,必须安装XForwardedHeaderSupport功能 .

作为请求对象的一部分,有两个属性localorigin ,它们可以获取原始请求或本地/代理请求的信息.

val local : RequestConnectionPoint = request.local // Local information 
val origin: RequestConnectionPoint = request.origin // Local / Origin if XForwardedHeaderSupport feature is installed.

您可以获得的本地/来源信息:

interface RequestConnectionPoint {
    val scheme: String // "http" or "https": The provided protocol (local) or `X-Forwarded-Proto`
    val version: String // "HTTP/1.1"
    val port: Int
    val host: String // The provided host (local) or `X-Forwarded-Host`
    val uri: String
    val method: HttpMethod
    val remoteHost: String // The client IP (the direct ip for `local`, or the redirected one `X-Forwarded-For`)
}

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

您还可以访问原始queryStringparam1=value&param2=value ):

val queryString: String = request.queryString()

POST, PUT and PATCH

POSTPUTPATCH请求具有关联的请求主体(有效负载). 该有效载荷通常被编码.

所有接收方法都会消耗客户端发送的整个有效负载,因此,除非您已安装DoubleReceive功能,否则两次尝试接收请求正文都会导致RequestAlreadyConsumedException错误.

Raw payload

要访问有效负载的原始位,可以使用receiveChannel ,但这是call一部分,而不是call.request

val channel: ByteReadChannel = call.receiveChannel()

它为常见类型提供了一些方便的方法:

val channel: ByteReadChannel = call.receiveChannel()
val text: String = call.receiveText()
val inputStream: InputStream = call.receiveStream() // NOTE: InputStream is synchronous and blocks the thread
val multipart: MultiPartData = call.receiveMultipart()

所有那些receive *方法都是具有指定类型的call.receive<T>别名. ByteReadChannelByteArrayInputStreamMultiPartDataStringParameters类型由默认安装的ApplicationReceivePipeline.installDefaultTransformations处理.

Form Parameters (urlencoded or multipart)

要解析使用urlencode或多部分形式的表单,可以使用receiveParametersreceive<Parameters>

val postParameters: Parameters = call.receiveParameters()

Receive Typed Objects, Content-Type and JSON

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

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

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

install(ContentNegotiation) {
    gson {
        setDateFormat(DateFormat.LONG)
        setPrettyPrinting()
    }
}

如果将ContentNegotiation配置为使用gson,则需要包括ktor-gson工件:

compile("io.ktor:ktor-gson:$ktor_version")

然后,作为示例,您可以执行以下操作:

data class HelloWorld(val hello: String)

routing {
    post("/route") {
        val helloWorld = call.receive<HelloWorld>()
    }
}

请记住,您的类必须定义为顶级(在任何其他类或函数之外),以供Gson识别.

Multipart, Files and Uploads

检查上传部分.

Custom receive transformers

您可以通过调用application.receivePipeline.intercept(ApplicationReceivePipeline.Transform) { query ->然后调用proceedWith(ApplicationReceiveRequest(query.type, transformed))来创建自定义转换器, 就像ContentNegotiation功能一样 .

Cookies

有一个cookies属性可以访问客户端发送的Cookie标头,就像它是一个集合一样:

val cookies: RequestCookies = request.cookies
val mycookie: String? = request.cookies["mycookie"]

To handle sessions using cookies, have a look to the Sessions feature.

Headers

要访问标头,请求对象具有headers: Headers属性. 它实现了StringValues接口,其中每个键都可以具有与其关联的字符串列表.

val headers: Headers = request.headers
val header: String? = request.header("HeaderName") // To access a single header (first one if repeated)
val repeatedHeader: List<String>? = request.headers.getAll("HeaderName") // Multiple values

还有几种访问一些常见标头的便捷方法:

val contentType: ContentType = request.contentType() // Parsed Content-Tpe 
val contentCharset: Charset? = request.contentCharset() // Content-Type JVM charset
val authorization: String? = request.authorization() // Authorization header
val location: String? = request.location() // Location header
val accept: String? = request.accept() // Accept header
val acceptItems: List<HeaderValue> = request.acceptItems() // Parsed items of Accept header
val acceptEncoding: String? = request.acceptEncoding() // Accept-Encoding header
val acceptEncodingItems: List<HeaderValue> = request.acceptEncodingItems() // Parsed Accept-Encoding items 
val acceptLanguage: String? = request.acceptLanguage() // Accept-Language header
val acceptLanguageItems: List<HeaderValue> = request.acceptLanguageItems() // Parsed Accept-Language items
val acceptCharset: String? = request.acceptCharset() // Accept-Charset header
val acceptCharsetItems: List<HeaderValue> = request.acceptCharsetItems() // Parsed Accept-Charset items
val userAgent: String? = request.userAgent() // User-Agent header
val cacheControl: String? = request.cacheControl() // Cache-Control header
val ranges: RangesSpecifier? = request.ranges() // Parsed Ranges header

val isChunked: Boolean = request.isChunked() // Transfer-Encoding: chunked
val isMultipart: Boolean = request.isMultipart() // Content-Type matches Multipart

by  ICOPY.SITE