Ktor: Content-Type in a request headers

Created on 14 May 2019  路  12Comments  路  Source: ktorio/ktor

Ktor Version

1.1.4

Ktor Engine Used(client or server and name)

Apache

JVM Version, Operating System and Relevant Context

1.8, macOS Mojave and Linux Mint, IDEA 2019.1.2 CE

Feedback

I'm accessing and API that requires me to set Content-Type for all requests, but I'm getting io.ktor.http.UnsafeHeaderException: Header Content-Type is controlled by the engine and cannot be set explicitly

Current implementation:

val client = HttpClient(Apache) {
        install(JsonFeature) {
            serializer = GsonSerializer()
        }
        install(Logging) {
            level = LogLevel.HEADERS
        }
        defaultRequest {
            header("Content-Type", "application/vnd.api+json")
        }
    }
get("/test") {
            client.get<String>("url...") {
                headers {
                    // other headers
                }
            }
        }
ux

Most helpful comment

I can't use Ktor client just because I'm unable to set Content-Type. Even your examples doesn't work:

   val message = client.post<HelloWorld> {
      url("http://127.0.0.1:8080/")
      contentType(ContentType.Application.Json)
      body = HelloWorld(hello = "world")
   }

All 12 comments

As an additional information, I can solve this issue by using OkHttp with a network interceptor, but I'm curious how to do the same thing using Apache client

Hi @mister11, thanks for the report.
We introduced acceptContentTypes in JsonFeature since 1.2.0. It provides you possibility to set custom Accept and Content-Type headers automatically.

Could you check and report if it solves your problem?

Not sure if I'm doing something wrong, but this is not working:

val client = HttpClient(Apache) {
        install(JsonFeature) {
            serializer = GsonSerializer()
            acceptContentTypes = acceptContentTypes + listOf(ContentType.parse("application/vnd.api+json; ext=bulk"))
        }
    }

This just sets Accept header and I need Content-Type header for requests.

To make it more clear, here is a working version of OkHttp interceptor implementation:

fun provideHeadersInterceptor() = Interceptor { chain ->
    val requestBuilder = chain.request().newBuilder()
        .addHeader("Content-Type", "application/vnd.api+json")

    chain.proceed(requestBuilder.build())
}
fun provideOkHttpClient(): HttpClient = HttpClient(OkHttp) {
    engine {
        addNetworkInterceptor(provideHeadersInterceptor())
    }
}

any solutions? I am in the same situation, but for me even interceptior does not seem to work as I would expected and I'm getting

Exception in thread "main" java.lang.ClassCastException: class shared.model.ProductUpdateDto cannot be cast to class io.ktor.client.call.HttpClientCall (shared.model.ProductUpdateDto and io.ktor.client.call.HttpClientCall are in unnamed module of loader 'app')

I can't use Ktor client just because I'm unable to set Content-Type. Even your examples doesn't work:

   val message = client.post<HelloWorld> {
      url("http://127.0.0.1:8080/")
      contentType(ContentType.Application.Json)
      body = HelloWorld(hello = "world")
   }
Was this page helpful?
0 / 5 - 0 ratings