You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 05:09:03