往期导航:
简介:
RequestInterceptor请求拦截器是一个协议,用来在请求流程中拦截请求,并对请求进行一些必要的处理,这是一个组合协议:RequestAdapter请求适配器与RequestRetrier请求重试器。使用者可以自己实现请求拦截器,根据自己的需求适配URLRequest,或者定义自己的重试逻辑,也可以使用Alamofire默认实现的简易适配器,设置组合协议个人觉得是因为,RequestAdapter是对请求的拦截预处理,RequestRetrier是对响应重试的拦截预处理,刚好请求响应一对,组合起来作为统一的一个对象来在生成Request时传入使用。
RequestAdapter请求适配器:
只有一个方法,用来在Request创建好初始的URLRequest后,对URLRequest进行适配,适配处理前后均会告诉监听器对应的通知。
/// 入参为初始URLRequest, Session以及适配完成后的回调, 回调参数为Result对象, 可以为成功适配后的URLRequest对象, 也可以返回错误, 会向上抛出从创建requestAdaptationFailed错误
func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void)
RequestRetrier请求重试器
也是只有一个方法,用来在请求失败时,决定是直接抛出错误,还是依据一定的逻辑进行重试:
// 参数为: Request对象, Session, 请求失败的错误信息以及重试逻辑回调, 回调参数为重试逻辑, 调用者根据该逻辑决定重试行为
func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void)
RetryResult重试逻辑
定义了四个重试逻辑
public enum RetryResult {
/// 立刻重试
case retry
/// 延迟重试
case retryWithDelay(TimeInterval)
/// 不重试,直接完成请求
case doNotRetry
/// 不重试并抛出错误
case doNotRetryWithError(Error)
}
//扩展一下快速取得相关信息, 两个可选值属性方便快速做出判断
extension RetryResult {
/// 是否需要重试
var retryRequired: Bool {
switch self {
case .retry, .retryWithDelay: return true
default: return false
}
}
/// 延迟重试时间
var delay: TimeInterval? {
switch self {
case let .retryWithDelay(delay): return delay
default: return nil
}
}
/// 不重试并抛出错误时的错误信息
var error: Error? {
guard case let .doNotRetryWithError(error) = self else { return nil }
return error
}
}
组合生成RequestInterceptor
直接把两个协议组合在一起供外部实现
public protocol RequestInterceptor: RequestAdapter, RequestRetrier {}
//扩展一下,使得即便遵循协议也可以不实现方法,依旧不会报错
extension RequestInterceptor {
public func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
//直接返回原请求
completion(.success(urlRequest))
}
public func retry(_ request: Request,
for session: Session,
dueTo error: Error,
completion: @escaping (RetryResult) -> Void) {
//不重试
completion(.doNotRetry)
}
}
Alamofire预先定义的请求拦截器:
Alamofire预先定义了一些简易的拦截器,可以直接使用,也可以根据自己需求自行实现
1. Adapter:基于闭包的简易请求适配器:
// 先定义了一个用来适配请求的闭包:
public typealias AdaptHandler = (URLRequest, Session, _ completion: @escaping (Result<URLRequest, Error>) -> Void) -> Void
//然后实现基于闭包的请求适配器,只是简单的持有一个闭包来适配请求:
open class Adapter: RequestInterceptor {
private let adaptHandler: AdaptHandler
public init(_ adaptHandler: @escaping AdaptHandler) {
self.adaptHandler = adaptHandler
}
open func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
adaptHandler(urlRequest, session, completion)
}
}
2. Retrier:基于闭包的简易重试器:
//先定义了一个用来决定重试逻辑的闭包:
public typealias RetryHandler = (Request, Session, Error, _ completion: @escaping (RetryResult) -> Void) -> Void
//然后实现基于闭包的重试器:
open class Retrier: RequestInterceptor {
private let retryHandler: RetryHandler
public init(_ retryHandler: @escaping RetryHandler) {
self.retryHandler = retryHandler
}
open func retry(_ request: Request,
for session: Session,
dueTo error: Error,
completion: @escaping (RetryResult) -> Void) {
retryHandler(request, session, error, completion)
}
}
3. Interceptor:可以持有多个适配器与重试器
持有两个数组,一个保存适配器对象,一个保存重试器对象,然后重试的时候,挨个去处理,因此要注意传入时的顺序问题
open class Interceptor: RequestInterceptor {
/// 保存适配器, 有任何一个出现错误, 就会抛出错误
public let adapters: [RequestAdapter]
/// All `RequestRetrier`s associated with the instance. These retriers will be run one at a time until one triggers retry.
/// 保存重试器, 有任何一个出现了需要重试(立即重试或者延迟重试)就会停止, 然后抛出需要重试. 有任何一个不重试并抛出错误也会停止, 并抛出错误.
public let retriers: [RequestRetrier]
/// 也可以使用重试器与适配器回调来创建单个的组合器
public init(adaptHandler: @escaping AdaptHandler, retryHandler: @escaping RetryHandler) {
adapters = [Adapter(adaptHandler)]
retriers = [Retrier(retryHandler)]
}
/// 用两个数组初始化
public init(adapter: RequestAdapter, retrier: RequestRetrier) {
adapters = [adapter]
retriers = [retrier]
}
/// 用适配器+重试器+拦截器数组初始化, 会把拦截器数组均加入到适配器与重试器数组中
public init(adapters: [RequestAdapter] = [], retriers: [RequestRetrier] = [], interceptors: [RequestInterceptor] = []) {
self.adapters = adapters + interceptors
self.retriers = retriers + interceptors
}
/// 适配器代理方法, 调下面的私有方法
open func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
adapt(urlRequest, for: session, using: adapters, completion: completion)
}
/// 私有适配方法, 会不停递归
private func adapt(_ urlRequest: URLRequest,
for session: Session,
using adapters: [RequestAdapter],
completion: @escaping (Result<URLRequest, Error>) -> Void) {
// 用来准备递归的数组
var pendingAdapters = adapters
// 递归空了就执行回调并返回
guard !pendingAdapters.isEmpty else { completion(.success(urlRequest)); return }
// 取出第一个适配器
let adapter = pendingAdapters.removeFirst()
// 走你
adapter.adapt(urlRequest, for: session) { result in
switch result {
case let .success(urlRequest):
// 适配通过, 递归去适配剩下的
self.adapt(urlRequest, for: session, using: pendingAdapters, completion: completion)
case .failure:
// 适配失败, 直接抛出错误
completion(result)
}
}
}
// 重试器逻辑, 调下面私有方法
open func retry(_ request: Request,
for session: Session,
dueTo error: Error,
completion: @escaping (RetryResult) -> Void) {
retry(request, for: session, dueTo: error, using: retriers, completion: completion)
}
// 私有重试逻辑, 会递归调用
private func retry(_ request: Request,
for session: Session,
dueTo error: Error,
using retriers: [RequestRetrier],
completion: @escaping (RetryResult) -> Void) {
// 用来递归的重试器数组
var pendingRetriers = retriers
// 递归完成且没有触发重试或错误, 就返回不重试, 并返回不重试
guard !pendingRetriers.isEmpty else { completion(.doNotRetry); return }
// 取出第一个
let retrier = pendingRetriers.removeFirst()
// 走你
retrier.retry(request, for: session, dueTo: error) { result in
switch result {
case .retry, .retryWithDelay, .doNotRetryWithError:
// 重试, 延迟重试, 不重试并抛出错误的话, 执行回调
completion(result)
case .doNotRetry:
// 否则开始递归
self.retry(request, for: session, dueTo: error, using: pendingRetriers, completion: completion)
}
}
}
}
以上纯属个人理解,难免有错误,如果发现有错,欢迎评论指出~~将第一时间改正,也欢迎评论讨论,非常感谢~~