4、Ktor學習-處理HTTP請求;

Melrose發表於2019-03-04

  處理路由或直接攔截管道時,您將獲得ApplicationCall的上下文。 該呼叫包含一個名為request的屬性,其中包含有關請求的資訊。

介紹

  當使用路由功能或攔截請求時,您可以訪問處理程式內的call屬性。 該呼叫包括一個請求屬性,其中包含有關請求的相關資訊:

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

intercept(ApplicationCallPipeline.Call) { 
    if (call.request.uri == "/") {
        call.respondText("Test String")
    }
}
複製程式碼

請求資訊

  作為請求的一部分,您可以訪問其內部上下文:

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
複製程式碼

反向代理支援:origin和local

  當在反向代理(例如nginx或負載均衡器)後面時,終端使用者不會執行接收到的請求,而是反向代理。 這意味著連線的客戶端IP地址將是代理而不是客戶端之一。 反向代理也可能通過HTTPS提供服務並通過HTTP向您的伺服器請求。 流行的反向代理髮送X-Forwarded-標頭以便能夠訪問此資訊。

注:請注意,為了在反向代理下工作,您必須安裝XForwardedHeaderSupport功能。

  作為請求物件的一部分,有兩個屬性local和origin,它們允許獲取原始請求或本地/代理請求的資訊。

val local : RequestConnectionPoint = request.local // Local information 
val origin: RequestConnectionPoint = request.origin // Local / Origin if XForwardedHeaderSupport feature is installed.
複製程式碼

  您可以獲得的local/origin資訊:

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引數

  如果需要訪問查詢引數?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

  POST,PUT和PATCH請求具有關聯的請求主體(有效負載)。

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()
複製程式碼

表單引數(urlencoded或multipart)

要解析urlencoded或multipart的表單,可以使用receiveParameters或receive <Parameters>:

val postParameters: Parameters = call.receiveParameters()
複製程式碼

接收型別物件,內容型別和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識別。

Cookies

  有一個cookie屬性可以訪問客戶端傳送的Cookie標頭,就像它是一個集合一樣:

val cookies: RequestCookies = request.cookies
val mycookie: String? = request.cookies["mycookie"]
複製程式碼

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
複製程式碼

相關文章