如何在OkHttp拦截器中流式解码响应体处理后端自定义错误?
流式解析自定义错误码:OkHttp拦截器优化实现
可行,而且能有效避免一次性读取整个响应体带来的内存开销。核心思路是利用OkHttp的BufferedSource结合JSON库的流式解析能力,只读取到errorcode字段就停止判断,无需加载完整响应内容。
问题分析
你当前的实现用peekBody(Long.MAX_VALUE)会把整个响应体加载到内存,对于大体积响应(比如包含大量数据的列表接口),会造成不必要的内存占用和IO消耗。流式解析可以在读取到目标字段后立即终止解析,大幅提升性能。
优化实现(基于kotlinx.serialization)
利用kotlinx.serialization的StreamingJsonDecoder实现流式读取,同时保证后续Retrofit能正常解析完整响应体:
import kotlinx.serialization.StreamingJsonDecoder import kotlinx.serialization.json.Json import okhttp3.Interceptor import okhttp3.Response import okhttp3.ResponseBody import okio.BufferedSource @Throws(BackendError::class) private fun responseBodyInterceptor(json: Json) = Interceptor { chain -> val originalResponse = chain.proceed(chain.request()) val originalBody = originalResponse.body ?: return@Interceptor originalResponse // 仅处理JSON格式的响应 val contentType = originalBody.contentType() if (contentType?.subtype?.equals("json", ignoreCase = true) != true) { return@Interceptor originalResponse } val bufferedSource = originalBody.source().buffer() var errorCode: String? = null try { // 流式解析JSON,仅读取errorcode字段 json.decodeFromString(StreamingJsonDecoder(bufferedSource)) { beginObject() while (hasNextElement()) { val key = nextName() if (key == "errorcode") { errorCode = nextString() // 跳过当前字段的剩余内容,终止解析 skipElement() break } else { // 跳过无关字段,不读取完整内容 skipElement() } } endObject() } } catch (e: Exception) { // JSON格式异常时,返回原始响应 bufferedSource.close() return@Interceptor originalResponse } errorCode?.let { // 发现错误码,关闭资源并抛出异常 originalBody.close() throw BackendError(it) } // 重置流位置,让后续Retrofit能正常读取完整响应体 bufferedSource.reset() // 返回包装后的响应体,保证资源正常释放 originalResponse.newBuilder() .body(object : ResponseBody() { override fun contentType() = originalBody.contentType() override fun contentLength() = originalBody.contentLength() override fun source() = bufferedSource }) .build() }
关键细节说明
- 流式解析终止:找到
errorcode字段后立刻调用skipElement()跳过剩余内容,无需读取整个JSON结构。 - 流位置重置:通过
bufferedSource.reset()将流指针恢复到起始位置,确保后续Retrofit解析完整响应体时不会丢失数据。 - 资源管理:抛出异常前必须关闭原始响应体,避免OkHttp连接池资源泄漏;正常流程下,包装后的响应体由Retrofit负责关闭。
- 格式校验:提前判断响应的Content-Type,避免非JSON响应触发解析异常。
版本要求
确保你的kotlinx.serialization版本≥1.3.0,StreamingJsonDecoder是在该版本后正式引入的API。
内容的提问来源于stack exchange,提问作者m.reiter
相关产品推荐
相关产品推荐

