RxSwift实现带最大次数限制的网络请求重试方案咨询
解决RxSwift中retry操作符实现网络请求重试的问题
看起来你遇到的核心卡点是:retry操作符默认只在Observable发送error事件时才会触发重试,但你的场景是接口返回success="fail"时需要重试——这属于正常响应结果,不是error,所以原代码没触发重试逻辑。下面我给你一步步拆解解决方案:
第一步:把"fail"响应转换成Error事件
要让retry生效,我们得先把接口返回的success="fail"这种“业务失败”的情况,转换成RxSwift能识别的Error事件。先定义一个自定义错误类型标记这种场景:
enum ApiError: Error { case requestFailed } // 假设你的接口响应模型是这样的(根据实际情况调整) struct ApiResponse: Decodable { let success: String }
接着在网络请求的Observable之后,用map操作符判断响应结果:如果success不是"ok",就抛出自定义错误;否则正常返回响应。
第二步:结合retry控制最大重试次数
用retry(_:)操作符设置最大重试次数时要注意:参数是重试的次数,不是总请求次数。比如你要最多重试5次,那总共有1(初始请求) + 5(重试)=6次请求机会;如果希望总请求次数是5次,参数就传4。
下面是完整的可运行代码示例(包含模拟网络请求,方便测试):
import RxSwift import RxCocoa let disposeBag = DisposeBag() // 模拟网络请求(替换成你实际的URLSession请求即可) func fetchApiData() -> Observable<ApiResponse> { // 模拟随机返回ok或fail,方便测试重试逻辑 let isSuccess = Bool.random() let response = ApiResponse(success: isSuccess ? "ok" : "fail") return Observable.just(response) .delay(.seconds(1), scheduler: ConcurrentDispatchQueueScheduler(qos: .background)) .observe(on: MainScheduler.instance) } // 核心重试逻辑 fetchApiData() .map { response -> ApiResponse in // 把业务失败转换成Error事件,触发retry机制 guard response.success == "ok" else { throw ApiError.requestFailed } return response } .retry(5) // 最多重试5次,总请求次数最多6次 .subscribe( onNext: { _ in print("queryedSuccess") // 这里处理请求成功后的业务逻辑 }, onError: { _ in print("queryedFail") // 这里处理重试5次后仍失败的业务逻辑 } ) .disposed(by: disposeBag)
进阶:添加重试间隔(可选)
如果需要在每次重试之间添加延迟(避免频繁请求服务器),可以用retryWhen替代retry,示例如下:
fetchApiData() .map { response -> ApiResponse in guard response.success == "ok" else { throw ApiError.requestFailed } return response } .retryWhen { errorObservable -> Observable<Int> in errorObservable.enumerated() .flatMap { attempt, error -> Observable<Int> in // 最多重试5次,超过上限就抛出原错误 guard attempt < 5 else { return Observable.error(error) } // 每次重试间隔2秒 return Observable.timer(.seconds(2), scheduler: MainScheduler.instance).map { _ in attempt } } } .subscribe( onNext: { _ in print("queryedSuccess") }, onError: { _ in print("queryedFail") } ) .disposed(by: disposeBag)
为什么你的原代码只执行一次?
因为你没有把success="fail"转换成Error事件,Observable一直处于正常的Next状态,retry操作符没有触发条件,所以只会执行一次请求。补上“业务失败转Error”的逻辑后,retry就能按预期工作了。
内容的提问来源于stack exchange,提问作者Zigii Wong
相关产品推荐
相关产品推荐

