Kotlin中如何正确解析换行分隔的JSON数组(基于OkHttpClient)
规范解析逐行JSON响应的实现方案
问题场景
我在Kotlin应用中使用OkHttpClient向API上传文件进行处理,API会持续返回消息保持连接存活,直到处理完成。返回内容为每行一个独立的JSON对象(即JSON Lines格式),示例如下:
{"status":"IN_PROGRESS","transcript":null,"error":null} {"status":"IN_PROGRESS","transcript":null,"error":null} {"status":"IN_PROGRESS","transcript":null,"error":null} {"status":"DONE","transcript":"Hello, world.","error":null}
此前通过字符串替换将其转为标准JSON数组再解析的方式,存在格式破坏风险(比如JSON字符串中包含}字符时会出错),需要更符合技术规范的实现方案。
方案一:逐行读取响应流并逐个解析
利用OkHttp响应体的字符流,逐行读取每个JSON对象,单独用Gson解析为Status实体。这种方式内存高效,且能实时处理每个状态更新。
代码实现
data class Status( val status: String?, val transcript: String?, val error: String? ) fun main() { val client = OkHttpClient() val requestBody = MultipartBody.Builder() .setType(MultipartBody.FORM) // 添加上传文件及参数,示例: // .addFormDataPart("file", "audio.mp3", File("path/to/file").asRequestBody()) .build() val request = Request.Builder() .url("http://localhost:8090") .post(requestBody) .build() client.newCall(request).execute().use { response -> if (!response.isSuccessful) throw IOException("请求失败: $response") val gson = Gson() val statusList = mutableListOf<Status>() // 逐行读取响应流 response.body?.charStream()?.buffered()?.useLines { lines -> lines.forEach { line -> if (line.isNotBlank()) { val status = gson.fromJson(line, Status::class.java) statusList.add(status) // 实时处理状态,比如打印进度或更新UI when (status.status) { "IN_PROGRESS" -> println("处理中...") "DONE" -> println("处理完成,转录内容:${status.transcript}") } } } } println("所有状态记录:$statusList") } }
方案二:使用Gson流式解析(JsonReader)
如果API返回的JSON对象之间没有严格换行(或存在格式小瑕疵),可以用Gson的JsonReader进行流式解析,逐个读取JSON对象,兼容性更强。
代码实现
data class Status( val status: String?, val transcript: String?, val error: String? ) fun main() { val client = OkHttpClient() val requestBody = MultipartBody.Builder() .setType(MultipartBody.FORM) // 添加上传文件及参数 .build() val request = Request.Builder() .url("http://localhost:8090") .post(requestBody) .build() client.newCall(request).execute().use { response -> if (!response.isSuccessful) throw IOException("请求失败: $response") val gson = Gson() val statusList = mutableListOf<Status>() response.body?.charStream()?.use { charStream -> JsonReader(charStream).use { reader -> reader.isLenient = true // 兼容非严格JSON格式 while (reader.hasNext()) { val status = gson.fromJson(reader, Status::class.java) statusList.add(status) if (status.status == "DONE") { println("处理完成:${status.transcript}") } } } } println("所有状态记录:$statusList") } }
方案优势
- 避免格式错误:不会因为JSON字符串中包含
}等特殊字符而破坏结构; - 内存高效:无需将整个响应读入内存,适合大响应或长连接场景;
- 实时处理:可在收到每个状态时立即处理,无需等待完整响应返回。
内容的提问来源于stack exchange,提问作者Jesser
相关产品推荐
相关产品推荐

