Retrofit请求返回URL编码字符串与HttpURLConnection结果不一致问题问询
问题1:为什么Retrofit会返回URL编码的字符串?
核心原因是ScalarsConverterFactory默认使用ISO-8859-1字符集解析响应字节流:
- 你原有
HttpURLConnection实现中,InputStreamReader未指定字符集时,默认使用当前环境的UTF-8字符集解析响应,能正确识别多字节的Unicode字符。 - 当服务端返回的响应实际为UTF-8编码,且未明确返回
Content-Type: text/plain; charset=utf-8响应头时,ScalarsConverterFactory会默认回退到ISO-8859-1解码,把UTF-8的多字节字符错误拆分为单个单字节字符,最终呈现出类似%C2 %96的类URL编码乱码效果,并非响应内容真的被做了URL编码。
问题2:如何正确解码该字符串以避免报错?
不要直接使用URLDecoder解码:你拿到的不是标准URL编码字符串,字符中间的空格会触发非法字符报错。正确做法是将错误编码的字符串转回原始字节数组,再用UTF-8重新解码:
val retrofitResult = api.getTranslation(sourceLanguage, targetLanguage, text) // 先转成ISO-8859-1对应的原始字节,再用UTF-8编码 val correctResult = String(retrofitResult.toByteArray(Charsets.ISO_8859_1), Charsets.UTF_8)
问题3:如何修改配置才能直接获取未编码的纯文本结果?
有两种可用方案,无需每次手动转码:
- 方案1(推荐,无服务端依赖):自定义UTF-8编码的字符串转换器
替换默认的ScalarsConverterFactory,强制用UTF-8解析所有字符串类型的响应:
// 自定义转换器实现 class Utf8StringConverterFactory : Converter.Factory() { companion object { fun create() = Utf8StringConverterFactory() } override fun responseBodyConverter( type: Type, annotations: Array<out Annotation>, retrofit: Retrofit ): Converter<ResponseBody, *>? { return if (type == String::class.java) { Converter<ResponseBody, String> { responseBody -> responseBody.use { body -> body.string(Charsets.UTF_8) } } } else null } } // 初始化Retrofit时替换原有ScalarsConverterFactory val retrofit = Retrofit.Builder() .baseUrl("你的接口根地址") .addConverterFactory(Utf8StringConverterFactory.create()) // 其他配置... .build()
- 方案2(需要服务端配合):调整响应头
修改服务端接口配置,返回响应时添加Content-Type: text/plain; charset=utf-8头,默认的ScalarsConverterFactory会自动识别字符集,无需修改客户端代码。
内容的提问来源于stack exchange,提问作者lobzik
相关产品推荐
相关产品推荐

