Android Kotlin用OkHttp Retrofit拦截器处理超大API响应体问题
OkHttp拦截器压缩带大量表情的响应解决方案
你当前的实现仅对响应长度做了数值减法,既没有读取响应内容完成表情过滤,也没有按照OkHttp规范构造ResponseBody实例,因此无法正常返回。以下是可直接运行的完整实现:
1. 先实现表情过滤工具方法
/** * 过滤字符串中的表情 * @param keepOnlyOne 传true仅保留1个表情,传false移除所有表情 */ fun String.filterEmoji(keepOnlyOne: Boolean = false): String { // 匹配绝大多数表情符号的正则 val emojiRegex = Regex("\\p{So}") return if (keepOnlyOne) { val firstEmoji = emojiRegex.find(this)?.value ?: "" emojiRegex.replace(this, "") + firstEmoji } else { emojiRegex.replace(this, "") } }
2. 完整拦截器实现
import okhttp3.Interceptor import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.Response import okhttp3.ResponseBody.Companion.toResponseBody import okio.IOException class EmojiCompressInterceptor : Interceptor { @Throws(IOException::class) override fun intercept(chain: Interceptor.Chain): Response { val originalRequest = chain.request() val originalResponse = chain.proceed(originalRequest) val originalBody = originalResponse.body ?: return originalResponse // 替换为你要处理的问题接口路径,避免所有接口都走处理逻辑影响性能 val targetApiPath = "/your/target/api/path" if (!originalRequest.url.encodedPath.contains(targetApiPath)) { return originalResponse } // 仅处理大于500KB的响应,可按需调整阈值 if (originalBody.contentLength() <= 500 * 1024) { return originalResponse } // 读取原响应内容,注意string()方法只能调用一次,调用后原响应体自动关闭 val originalContent = originalBody.string() // 按需选择是否保留1个表情 val processedContent = originalContent.filterEmoji(keepOnlyOne = false) // 构造新的响应体,保持原有响应的content-type val newResponseBody = processedContent.toResponseBody(originalBody.contentType()) // 返回替换后的新响应 return originalResponse.newBuilder() .body(newResponseBody) // 移除旧的Content-Length头,OkHttp会自动计算新的响应长度 .removeHeader("Content-Length") .build() } }
3. 注意事项
- 如果你要处理的接口返回非UTF-8编码,在调用
toResponseBody时需要额外指定编码参数 - 若现有正则匹配不全你遇到的表情,可以自行扩展正则匹配规则
- 一定要添加目标接口路径判断,避免所有接口都执行字符串处理逻辑拖慢请求速度
内容的提问来源于stack exchange,提问作者SilverSpoonie
相关产品推荐
相关产品推荐

