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

Kotlin+Reactor实现Gitlab分页Commits API遇无结果异常问题

解决Kotlin+Reactor调用Gitlab Commits API空结果异常问题

嘿,我来帮你搞定这个问题!你遇到的情况是:当两个提交哈希之间没有匹配的提交记录时,现有代码会抛出RuntimeException: Reached end of commit log,而你想通过switchIfEmpty来优雅处理这个空场景对吧?

问题根源分析

之前的异常大概率是因为你在分页遍历的过程中,一旦某一页返回空就直接抛出了异常,但正确的逻辑应该是遍历完所有分页后,确认整个流确实没有匹配结果时,再用switchIfEmpty处理。

修正后的代码示例

假设你已经有了调用单页Gitlab Commits API的函数,下面是处理两个哈希间提交、并正确处理空结果的完整实现:

// 先定义Gitlab提交数据类(根据API返回结构调整)
data class GitlabCommit(val id: String, val message: String, val authorName: String)

// 调用Gitlab单页提交API的函数
private fun getCommitsPage(projectId: String, page: Int, perPage: Int = 100): Flux<GitlabCommit> {
    return webClient.get()
        .uri("/projects/{projectId}/commits?page={page}&per_page={perPage}", projectId, page, perPage)
        .retrieve()
        .onStatus({ it.isError }) { clientResponse ->
            // 统一处理API错误,比如404、500等
            clientResponse.bodyToMono(String::class.java)
                .map { errorMsg -> RuntimeException("Gitlab API error: $errorMsg") }
        }
        .bodyToFlux(GitlabCommit::class.java)
}

// 获取两个提交哈希之间的记录,正确处理空结果
fun getCommitsBetween(projectId: String, startHash: String, endHash: String): Flux<GitlabCommit> {
    return Flux.generate(
        { 1 }, // 初始页码从1开始
        { currentPage, sink ->
            getCommitsPage(projectId, currentPage)
                .collectList()
                .subscribe({ pageCommits ->
                    when {
                        // 没有更多分页了,结束遍历
                        pageCommits.isEmpty() -> sink.complete()
                        // 当前页包含起始哈希,过滤到该哈希为止并结束
                        pageCommits.any { it.id == startHash } -> {
                            val filtered = pageCommits.takeWhile { it.id != startHash }
                                .filter { it.id != endHash } // 排除结束哈希本身
                            filtered.forEach(sink::next)
                            sink.complete()
                        }
                        // 当前页不包含起始哈希,过滤掉结束哈希后全部输出,继续下一页
                        else -> {
                            val filtered = pageCommits.filter { it.id != endHash }
                            filtered.forEach(sink::next)
                            sink.next(currentPage + 1)
                        }
                    }
                }, { error ->
                    // 传递API调用过程中的错误
                    sink.error(error)
                })
        }
    )
        .flatMapIterable { it } // 将分页的提交列表展开为Flux
        // 核心:当整个流为空时的处理逻辑,二选一即可
        .switchIfEmpty(Flux.empty()) // 选项1:返回空流,上层自行处理空场景
        // .switchIfEmpty(Flux.error(RuntimeException("No commits found between $startHash and $endHash"))) // 选项2:抛出自定义异常
}

关键优化点

  1. 分页遍历逻辑:用Flux.generate来逐页遍历Gitlab API,直到没有更多页或者找到起始哈希,避免提前抛出异常。
  2. 空结果触发时机:只有当所有分页都遍历完成、且没有任何匹配的提交时,switchIfEmpty才会生效,这才是正确的空场景判断时机。
  3. 错误统一处理:在getCommitsPage里通过onStatus处理API的错误响应,避免未捕获的异常中断流程。
  4. 灵活的空结果处理:你可以选择返回空流让上层处理,或者直接抛出自定义异常,完全根据业务需求调整。

额外注意事项

  • Gitlab API的per_page参数最大支持100,设置成100可以减少分页请求次数。
  • 要确认提交哈希的顺序:如果startHash是比endHash更新的提交,当前逻辑是从新到旧遍历,如果你需要反向遍历,需要调整API的order_by和sort参数(比如order_by=created_at&sort=asc)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 10:17:04