Generating HTTP Responses

预计阅读时间:6分钟

在处理路由或直接拦截管道时,您将获得一个带有ApplicationCall的上下文. 该call包含一个名为response的属性,该属性使您可以发出响应.

同样,调用本身具有一些有用的便利属性和与响应交互的方法.

目录:

Context

使用路由功能时,可以在路由处理程序中访问call属性:

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

当拦截请求,在lambda处理程序interceptcall可用的属性太:

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

Controlling the HTTP headers and the status

您可以控制响应的生成方式,HTTP状态,标头,cookie和有效负载.

请记住,由于HTTP请求的响应是不可搜索的流,因此一旦开始发出响应有效负载/内容,就会发出状态和标头,并且您将无法修改状态或标头/ cookie.

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

  • val call: ApplicationCall = response.call
  • val pipeline: ApplicationSendPipeline = response.pipeline

Headers:

  • val headers: ResponseHeaders = response.headers

便利性cookies实例,用于设置Set-Cookie标头:

  • val cookies: ResponseCookies = response.cookies

获取和更改HTTP状态:

  • response.status(HttpStatusCode.OK) -将HttpStatusCode设置为预定义的标准
  • response.status(HttpStatusCode(418, "I'm a tea pot")) -将HttpStatusCode设置为自定义状态代码
  • val status: HttpStatusCode? = response.status() val status: HttpStatusCode? = response.status() -如果设置,则获取当前设置的HttpStatusCode

  • response.contentType(ContentType.Text.Plain.withCharset(Charsets.UTF_8)) -用于设置Content-Type的类型化方法(对于ContentType.Application.Json ,默认字符集为UTF_8,但未明确显示)
  • response.contentType("application/json; charset=UTF-8") -设置Content-Type标头的无类型方式

自定义标题:

  • response.header("X-My-Header", "my value") -附加自定义标头
  • response.header("X-My-Times", 1000) -追加自定义标头
  • response.header("X-My-Times", 1000L) -附加自定义标头
  • response.header("X-My-Date", Instant.EPOCH) -附加自定义标头

设置标头的便捷方法通常由基础结构设置:

  • response.etag("33a64df551425fcc55e4d42a148795d9f25f89d4") -设置用于缓存的ETag
  • response.lastModified(ZonedDateTime.now()) -设置Last-Modified标头
  • response.contentLength(1024L) -设置Content-Length . 通常在发送有效负载时自动设置
  • response.cacheControl(CacheControl.NoCache(CacheControl.Visibility.Private)) -以键入方式设置Cache-Control标头
  • response.expires(LocalDateTime.now()) -设置Expires标头
  • response.contentRange(1024L until 2048L, 4096L) -设置Content-Range标头(检查PartialContent功能)

HTTP/2 pushing and HTTP/1 Link header

call支持推送.

  • 在HTTP / 2中,它使用推送功能
  • 在HTTP / 1.2中,它将Link标头添加为提示
routing {
    get("/") {
        call.push("/style.css")
    }
}

推送减少了请求和页面显示之间的时间. 但是请注意,事先发送内容可能会发送客户端已经缓存的内容.

Redirections

您可以使用respondRedirect方法轻松生成重定向响应,以发送带有" Location标头的" 301 Moved Permanently或" 302 Found重定向.

call.respondRedirect("/moved/here", permanent = true)

请记住,一旦执行了此功能,其余功能仍将执行. 因此,如果在guard子句中有它,则应从函数中返回以避免继续处理程序的其余部分. 如果要通过引发异常来进行重定向以停止控制流,请从状态页中检出此样本 .

Sending response content

发送通用内容(与" 内容协商"兼容):

  • call.respond(MyDataClass("hello", "world")) -检查" 内容协商"部分
  • call.respond(HttpStatusCode.NotFound, MyDataClass("hello", "world")) -指定状态码,并在单个调用中发送有效负载. 检查状态

发送纯文本:

  • call.respondText("text") -带有主体的字符串
  • call.respondText("p { background: red; }", contentType = ContentType.Text.CSS, status = HttpStatusCode.OK) { ... } -发送文本,指定ContentType,HTTP状态并配置OutgoingContent
  • call.respondText { "string" } -使用挂起提供程序响应字符串
  • call.respondText(contentType = ..., status = ...) { "string" } -使用挂起提供程序响应字符串
  • call.respond(TextContent("{}", ContentType.Application.Json)) -响应字符串,而不向Content-Type添加字符集

发送字节数组:

  • call.respondBytes(byteArrayOf(1, 2, 3)) -具有二进制主体的ByteArray

发送文件:

  • call.respondFile(File("/path/to/file")) -发送文件
  • call.respondFile(File("basedir"), "filename") { ... } -发送文件并配置OutgoingContent

发送URL编码的表单( application/x-www-form-urlencoded ):

  • 使用Parameters.formUrlEncode . 查看" 实用程序"页面以获取有关此信息的更多信息.

根据请求参数发送文件时,请特别小心地验证和限制输入.

使用Writer发送分块内容:

  • call.respondWrite { write("hello"); write("world") } call.respondWrite { write("hello"); write("world") } -使用call.respondWrite { write("hello"); write("world") }发送文本. 与HTML DSL一起使用
  • call.respondWrite(contentType = ..., status = ...) { write("hello"); write("world") } call.respondWrite(contentType = ..., status = ...) { write("hello"); write("world") } -使用call.respondWrite(contentType = ..., status = ...) { write("hello"); write("world") }发送文本并指定contentType和状态

使用WriteChannelContent发送任意数据:

call.respond(object : OutgoingContent.WriteChannelContent() {
    override val contentType = ContentType.Application.OctetStream
    override suspend fun writeTo(channel: ByteWriteChannel) {
        channel.writeFully(byteArray1)
        channel.writeFully(byteArray2)
        // ...
    }
})

要为请求指定默认内容类型:

  • call.defaultTextContentType(contentType: ContentType?): ContentType

用于配置响应的OutgoingContent接口:

class OutgoingContent {
    val contentType: ContentType? get() = null // * Specifies [ContentType] for this resource.
    val contentLength: Long? get() = null // Specifies content length in bytes for this resource. - If null, the resources will be sent as `Transfer-Encoding: chunked` 
    val status: HttpStatusCode? // Status code to set when sending this content
    val headers: Headers // Headers to set when sending this content
    fun <T : Any> getProperty(key: AttributeKey<T>): T? = extensionProperties?.getOrNull(key) // Gets an extension property for this content
    fun <T : Any> setProperty(key: AttributeKey<T>, value: T?) // Sets an extension property for this content
}

Making files downloadable

通过添加Content-Disposition标头 ,可以使文件"可下载".

您可以采用无类型的方式执行以下操作:

call.response.header(HttpHeaders.ContentDisposition, "attachment; filename=\"myfilename.bin\"")

但是Ktor还提供了一种带有适当转义的类型化方式来生成此标头:

call.response.header(HttpHeaders.ContentDisposition, ContentDisposition.Attachment.withParameter(ContentDisposition.Parameters.FileName, "myfilename.bin").toString())

Content negotiation

在配置用于内容协商的插件时,管道可以接受call.respond方法的其他类型.

Sending HTML with the DSL

Ktor包括一项可选功能,可使用DSL发送HTML内容 .

Sending HTML with FreeMarker

Ktor includes an optional feature to send HTML content using FreeMarker.

Sending JSON with data classes

Ktor包含一项可选功能,可使用"内容协商"发送JSON内容 .

by  ICOPY.SITE