Content conversion based on Content-Type and Accept headers

预计阅读时间: 3 分钟

This feature provides automatic content conversion according to Content-Type and Accept headers.

本特性在 io.ktor.features.ContentNegotiation 类中定义,无需任何额外构件。

Basic Usage

The ContentNegotiation feature allows you to register and configure custom converters.

install(ContentNegotiation) {
    register(MyContentType, MyContentTypeConverter()) {
        // Optionally configure the converter...
    }
}

For example:

install(ContentNegotiation) {
    register(ContentType.Application.Json, JacksonConverter())
}

Sending

When you respond with an object that is not directly handled, like a custom data class, this feature checks the client’s Accept header to determine which Content-Type will be used and thus which ContentConverter will be called.

call.respond(MyDataClass("hello", "world"))

Right now, the only supported ContentNegotiation strategy when sending, is the client’s Accept header. There is an issue to implement other strategies.

Receiving

When receiving, the Content-Type of the request will be used to determine which ContentConverter will be used to process that request:

val myDataClass = call.receive<MyDataClass>()

The ContentConverter interface

If you want to write your own converter, you have to implement the ContentConverter interface:

interface ContentConverter {
    suspend fun convertForSend(context: PipelineContext<Any, ApplicationCall>, contentType: ContentType, value: Any): Any?
    suspend fun convertForReceive(context: PipelineContext<ApplicationReceiveRequest, ApplicationCall>): Any?
}

For example, the GsonConverter implementation looks like:

class GsonConverter(private val gson: Gson = Gson()) : ContentConverter {
    override suspend fun convertForSend(context: PipelineContext<Any, ApplicationCall>, contentType: ContentType, value: Any): Any? {
        return TextContent(gson.toJson(value), contentType.withCharset(context.call.suitableCharset()))
    }

    override suspend fun convertForReceive(context: PipelineContext<ApplicationReceiveRequest, ApplicationCall>): Any? {
        val request = context.subject
        val channel = request.value as? ByteReadChannel ?: return null
        val reader = channel.readRemaining().readText((context.call.request.contentCharset() ?: Charsets.UTF_8).newDecoder()).reader()
        return gson.fromJson(reader, request.type.javaObjectType)
    }
}

Available out of the box ContentConverter

Ktor provide some content converters out of the box: