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

OkHttpClient连接池达150+时触发DataFormatException问题求助

问题:OkHttpClient连接池连接数达150+时抛出DataFormatException异常

我在服务中集成了OkHttpClient,当连接池中的连接数同时达到150+时,抛出了如下DataFormatException异常。请问是否有人了解该异常?如何修复此问题?是否与GZIP压缩有关?

错误信息

ResponseCode: 500 INTERNAL_SERVER_ERROR, ErrorMessage:ca.uhn.fhir.parser.DataFormatException: Failed to parse JSON encoded API content: Content does not appear to be API JSON, first non-whitespace character was: '<' (must be '{')

代码片段

private fun okhttpioConnection(): String {

    log.info("Initializing OKHttp-ioConnection")
    client = OkHttpClient()
    client.setConnectTimeout(600000, TimeUnit.MILLISECONDS)
    client.setReadTimeout(600000, TimeUnit.MILLISECONDS)
    client.connectionPool = ConnectionPool(300, 20000)
    client.retryOnConnectionFailure = true

    var request = createRequest(restParams) // GET or POST
    var response = client.newCall(request).execute()
    var responseCodeString = response.code().toString()
    return response.body()!!.string()

}
fun createRequest(restParams: RestParams): Request {
    if (restParams.method == "POST") {
      return Request.Builder()
        .post(RequestBody.create(
          MediaType.parse("application/json; charset=utf-8"), restParams.body.toString()))
        .header("Authorization", "xxxxxx")
        .addHeader("Content-Length",restParams.body.length.toString())
        .addHeader("Accept", "application/json, text/json")
        .url(restParams.url)
        .build()
    } else {
    return Request.Builder()
      .header("Authorization", "xxxxxxx")
      .addHeader("Accept", "application/json, text/json")
      .url(restParams.url).get()
      .build()
    }
  }

分析与解决方案

异常原因

从错误信息判断,服务端在连接数过高时返回了500内部错误,同时返回的内容是HTML格式(以<开头,大概率是服务端的错误页面),但你的代码默认将所有响应体当作JSON解析,因此触发了DataFormatException。本质是高负载下服务端无法正常处理请求,返回了非预期格式的错误响应。

是否与GZIP压缩有关

目前来看和GZIP压缩无关。如果是GZIP解压问题,通常会出现乱码或解压失败的异常,而非解析JSON时遇到<字符。除非服务端错误返回了GZIP压缩的HTML,但这种情况概率极低,暂不考虑。

修复方案

  1. 先校验响应状态再解析
    在获取响应体之前,先判断响应是否成功(200-299状态码),如果是错误状态,直接捕获处理,避免解析错误格式的内容:

    var response = client.newCall(request).execute()
    if (!response.isSuccessful) {
        val errorBody = response.body()?.string() ?: "Empty error body"
        log.error("Request failed, code: ${response.code()}, error content: $errorBody")
        // 抛出业务异常或返回错误标识,不要继续解析JSON
        throw RuntimeException("Server returned error: ${response.code()}")
    }
    return response.body()!!.string()
    
  2. 优化连接池配置
    当前设置的300个连接可能超出了服务端的承载上限,导致服务端过载。建议降低最大连接数(比如调整到100以内),同时缩短连接空闲超时时间,避免无效连接占用资源:

    client.connectionPool = ConnectionPool(100, 10000) // 示例配置,根据实际业务调整
    
  3. 复用OkHttpClient实例
    你的代码每次调用okhttpioConnection()都会创建新的OkHttpClient实例,导致多个连接池并存,无法有效复用连接。应该将OkHttpClient做成全局单例:

    // 全局单例初始化
    private val client by lazy {
        OkHttpClient.Builder()
            .connectTimeout(600000, TimeUnit.MILLISECONDS)
            .readTimeout(600000, TimeUnit.MILLISECONDS)
            .connectionPool(ConnectionPool(100, 10000))
            .retryOnConnectionFailure(true)
            .build()
    }
    
    private fun okhttpioConnection(): String {
        log.info("Initializing OKHttp-ioConnection")
        val request = createRequest(restParams)
        val response = client.newCall(request).execute()
        // 后续响应处理逻辑
    }
    
  4. 排查服务端负载瓶颈
    连接数过高时服务端返回500,说明服务端在高负载下稳定性不足。需要配合服务端团队排查:是否存在接口性能瓶颈、数据库连接池不足、线程资源耗尽等问题,从根源解决高负载下的服务异常。


内容的提问来源于stack exchange,提问作者Kaushik KR

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 21:25:18