xani
xani

Reputation: 804

How to specify Get-Request encoding (Retrofit + OkHttp)

I'm using Retrofit2 + OkHttp3 in my Android app to make a GET - Request to a REST-Server. The problem is that the server doesn't specify the encoding of the JSON it delivers. This results in an 'é' being received as '�' (the Unicode replacement character).

Is there a way to tell Retrofit or OkHttp which encoding the response has?

This is how I initialize Retrofit (Kotlin code):

val gson = GsonBuilder()
        .setDateFormat("d.M.yyyy")
        .create()

val client = OkHttpClient.Builder()
        .build()

val retrofit = Retrofit.Builder()
        .baseUrl(RestService.BASE_URL)
        .client(client)
        .addConverterFactory(GsonConverterFactory.create(gson))
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .build()

val rest = retrofit.create(RestService::class.java)

PS: The server isn't mine. So I cannot fix the initial problem on the server side.

Edit: The final solution

class EncodingInterceptor : Interceptor {

    override fun intercept(chain: Interceptor.Chain): Response {
        val response = chain.proceed(chain.request())
        val mediaType = MediaType.parse("application/json; charset=iso-8859-1")
        val modifiedBody = ResponseBody.create(mediaType, response.body().bytes())
        val modifiedResponse = response.newBuilder()
                .body(modifiedBody)
                .build()

        return modifiedResponse
    }
}

Upvotes: 15

Views: 17747

Answers (3)

Alvaro Sanz Rodrigo
Alvaro Sanz Rodrigo

Reputation: 21

This post is old but I found a solution that works for me in Kotlin (the answer of @BryanHerbst didn't quite worked for me)

class EncodingInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
    val response = chain.proceed(chain.request())
    var encodedBody = ""
    val encoding = InputStreamReader(
        response.body?.byteStream(),
        Charset.forName("ISO-8859-1")
    ).forEachLine {
        encodedBody += it
    }

    return response.newBuilder()
        .addHeader("Content-Type", "application/xml; charset=utf-8")
        .body(encodedBody.toResponseBody())
        .build()
    }
}

Upvotes: 0

Michał Ciołek
Michał Ciołek

Reputation: 329

class FixEncodingInterceptor implements Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {
        Response response = chain.proceed(chain.request());
        MediaType oldMediaType = MediaType.parse(response.header("Content-Type"));
        // update only charset in mediatype
        MediaType newMediaType = MediaType.parse(oldMediaType.type()+"/"+oldMediaType.subtype()+"; charset=windows-1250");
        // update body
        ResponseBody newResponseBody = ResponseBody.create(newMediaType, response.body().bytes());

        return response.newBuilder()
                .removeHeader("Content-Type")
                .addHeader("Content-Type", newMediaType.toString())
                .body(newResponseBody)
                .build();
    }
}

and add to OkHttp:

builder.addInterceptor(new FixEncodingInterceptor());

Upvotes: 1

Bryan Herbst
Bryan Herbst

Reputation: 67189

One way to do this is to build an Interceptor that takes the response and sets an appropriate Content-Type like so:

class ResponseInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val response = chain.proceed(chain.request())
        val modified = response.newBuilder()
                .addHeader("Content-Type", "application/json; charset=utf-8")
                .build()

        return modified
    }
}

You would add it to your OkHttp client like so:

val client = OkHttpClient.Builder()
        .addInterceptor(ResponseInterceptor())
        .build()

You should make sure you either only use this OkHttpClient for your API that has no encoding specified, or have the interceptor only add the header for the appropriate endpoints to avoid overwriting valid content type headers from other endpoints.

Upvotes: 10

Related Questions