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

ApolloClient watch方法异常无法捕获?原因及捕获方案

Apollo Watch方法异常捕获问题解析

问题场景

手动执行查询时,因错误服务器地址抛出的异常能被外层try/catch捕获:

try {
    val response = apolloClient.query(MyQuery()).execute()
} catch (e: Exception) {
    Timber.e("exception from manual execution")
    Timber.e(e)
}

但使用watch()方法执行相同查询时,外层try/catch无法捕获异常:

try {
    apolloClient.query(MyQuery())
        .watch() // 返回Flow
        .collect { response ->
            Timber.i("apollo watch collect called")
        }
} catch (e: Exception) {
    Timber.e("exception from watch execution")
    Timber.e(e)
}

问题根源

  • execute()是同步阻塞调用,所有异常都会直接在当前线程抛出,外层try/catch可以直接捕获。
  • watch()返回的是Flow类型,属于冷流,其异常传播规则和同步调用不同:流内部的异常不会直接抛到collect所在的外层代码中,而是被封装在流的发射逻辑里,外层的try/catch无法感知到流内部的异常。

正确捕获watch异常的方案

方案1:处理Response中的业务错误

Apollo的watch返回的Flow会优先发射包含错误信息的Response对象(而非直接抛异常),可以先判断Response状态:

apolloClient.query(MyQuery())
    .watch()
    .collect { response ->
        if (response.hasErrors()) {
            Timber.e("GraphQL请求错误: ${response.errors}")
        } else {
            Timber.i("apollo watch collect called")
            // 处理正常返回数据
        }
    }

方案2:使用Flow的异常处理操作符捕获底层异常

如果是网络连接失败这类严重底层异常,需要用Flow的catch操作符捕获:

apolloClient.query(MyQuery())
    .watch()
    .catch { e ->
        Timber.e("watch执行异常")
        Timber.e(e)
    }
    .collect { response ->
        if (!response.hasErrors()) {
            Timber.i("apollo watch collect called")
        }
    }

方案3:在collect内部嵌套try/catch(不推荐)

也可以在collect的lambda中直接捕获异常,但这种方式不够优雅,适合简单场景:

apolloClient.query(MyQuery())
    .watch()
    .collect { response ->
        try {
            if (!response.hasErrors()) {
                Timber.i("apollo watch collect called")
            }
        } catch (e: Exception) {
            Timber.e(e)
        }
    }

内容的提问来源于stack exchange,提问作者me.at.coding

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 22:27:43