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

如何使用Retrofit发起多POST请求并接收响应校验提交状态?

批量POST请求的最佳实现方案

核心优化方向

  • 并发执行请求:避免串行请求拖慢效率,用协程并发处理同时控制请求数量,防止服务器过载
  • 保留请求关联信息:不要只返回布尔值,返回包含原数据和结果的对象,方便定位成功/失败的具体项
  • 完善异常处理:单个请求失败不中断整体流程,捕获异常并标记为失败
  • 优化流的构建逻辑:避免嵌套collect的冗余写法,用更简洁的Flow操作符处理数据

优化后的代码示例

首先定义承载结果的数据类,关联原数据与提交状态:

data class WeightSubmitResult(
    val weight: Weight, // 替换为你的Weight实体类
    val isSuccess: Boolean,
    val errorMessage: String? = null
)

然后实现批量提交函数:

private suspend fun submitConfirmWeights(): Flow<WeightSubmitResult> = flow {
    // 获取离线数据集合(如果是持续发射的Flow,可改用first()获取当前快照)
    val offlineWeights = syncRepositoryImpl.getOfflineShopCollections().first()
    
    coroutineScope {
        // 并发执行请求,默认使用Dispatcher.IO的并发限制
        val deferredResults = offlineWeights.map { weight ->
            async {
                runCatching {
                    val dto = confirmWeightsDtoMapper.mapFromDomainModel(weight)
                    val response = confirmWeightsService.confirmWeights(dto)
                    // 判断请求成功且业务状态正常
                    response.isSuccessful && response.body()?.status == true
                }.fold(
                    onSuccess = { isSuccess ->
                        WeightSubmitResult(weight, isSuccess)
                    },
                    onFailure = { error ->
                        WeightSubmitResult(weight, false, error.localizedMessage)
                    }
                )
            }
        }
        // 等待所有请求完成,逐个发射结果
        deferredResults.forEach { deferred ->
            emit(deferred.await())
        }
    }
}

关键细节补充

  • 自定义并发数:如果需要限制同时发起的请求数(比如最多5个),可以用信号量控制:
    val semaphore = Semaphore(5)
    // 在async内部添加许可控制
    async {
        semaphore.withPermit {
            // 执行请求逻辑
        }
    }
    
  • 响应实时数据更新:如果getOfflineShopCollections()是监听数据库变化的Flow,可改用flatMapConcat响应新数据:
    private fun submitConfirmWeights(): Flow<WeightSubmitResult> =
        syncRepositoryImpl.getOfflineShopCollections()
            .flatMapConcat { weights ->
                flow {
                    // 内部执行上述并发请求逻辑
                }
            }
    
  • 结果处理示例:调用方可以精准处理成功/失败项:
    viewModelScope.launch {
        submitConfirmWeights().collect { result ->
            if (result.isSuccess) {
                // 成功逻辑:比如从离线库删除该数据
                syncRepositoryImpl.removeOfflineWeight(result.weight)
            } else {
                // 失败逻辑:比如记录错误或标记待重试
                Log.e("Submit", "提交失败[${result.weight.id}]: ${result.errorMessage}")
            }
        }
    }
    

原代码的问题分析

  1. 串行执行效率低:forEach逐个同步发起请求,批量数据多时耗时过长
  2. 结果无关联:仅发射布尔值,无法对应到具体的Weight数据,后续无法精准处理
  3. 异常无防护:单个请求抛出异常会中断整个Flow,导致后续请求无法执行
  4. Flow嵌套冗余:在flow内部调用collect,流的生命周期管理复杂,不如直接用Flow操作符简洁

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 22:40:41