Reputation: 804
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
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
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
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