上篇,我们梳理了Alamofire
的工作流程。今天我们继续研究,这次主要梳理RequestInterceptor
(拦截器)的相关内容。
RequestInterceptor
是一个协议,它本身没有任何要求,只是遵循了和两个协议:
1 |
|
也就是说,要想实现一个拦截器,满足RequestAdapter
和RequestRetrier
即可。下面分别瞅瞅这俩各有什么要求。
RequestAdapter
RequestAdapter
是一个请求适配器。对于一个请求,我们可以通过Adapter
来决定如何操作该请求。具体定义如下:
1 |
|
如果我们将一个http
请求事务划分为两个阶段:请求发送之前
和收到响应之后
,那么这里的RequestAdapter
就作用在第一阶段的。RequestRetrier
是否作用于第二阶段呢?一起往下看。
RequestRetrier
1 |
|
可以看到这里确实是作用在收到响应之后,只不过限制了在失败的场景。
这里可能的处理方式有 4 种:
1 |
|
我只需将具体的处理方式通过completion
回调回去即可实现对应的效果。
好了,静态的部分暂时分析这么多,下面瞅瞅RequestInterceptor
是如何运行的。
RequestInterceptor 是如何工作的
为了观察RequestInterceptor
的工作方式,我新建了一个SignRequestInterceptor
,用来完成对请求的签名,将签名通过请求头传递:
RequestInterceptor 的单元测试有点复杂,对于理解 RequestInterceptor 是个负担,所有这里使用我们自己写的例子。
1 |
|
有了自己的RequestInterceptor
后,我们有两种方式去使用它:
-
Session
级别,在生成自己的Session
时同时并配置Interceptor
:let session = Session(interceptor: SignRequestInterceptor())
。这种方式配置的,会作用于该Session
创建的每一个Request
上。 -
Request
级别,在构建请求实例时,传入:AF.request("https://httpbin.org/post", interceptor: SignRequestInterceptor())
。这种方式配置的只作用于当前Request
。
RequestAdapter 工作流程
我们在这里打上断点:
1 |
|
发起请求后可以看到如下调用栈:
这里是我们上篇讲到的最后的请求配置阶段,在该阶段,我们的Interceptor
得以调用。如何处置就看大家的想象了。
RequestRetrier 工作流程
同样,我们在下面的方法打上断点:
1 |
|
然后将网络断掉,模拟网络错误的情况。对应的调用栈如下:
可追溯到的调用起点是系统的回调方法:
SessionDelegate.urlSession(_:task:didCompleteWithError:)
。在分析具体实现之前,我们先了解下这里引入的几个新面孔:
SessionDelegate
:实现了众多URLSessionDelegate
,衔接系统框架和Alamofire
。它包含了几个重要的属性:
1 |
|
SessionStateProvider
:为了不直接使用Session
对象,这里使用SessionStateProvider
将Session
和SessionDelegate
隔离开。
1 |
|
下面是Session
对于该协议的实现:
1 |
|
-
EventMonitor
: 事件监听器。这也是一个协议,遵循该协议的可以成为事件监听器,可监听到URLSession
一系列代理事件和Request
生命周期内的各种事件。监听器的所有事件都有默认的实现,在对应的扩展中。同时,Alamofire
也提供了多个实现:CompositeEventMonitor
监听器的混合器,可以将多个监听器通过该类合并在一起。ClosureEventMonitor
闭包监听器,将EventMonitor
的各个方法通过闭包回调。NSLoggingEventMonitor
日志监听器,负责输出日志到控制台。AlamofireNotifications
通知监听器,负责将对应事件以通知的形式发出,这里只实现了部分监听方法。
-
RequestDelegate
: 和SessionStateProvider
类似,Request
通过该协议和Session
通信
1 |
|
下面是Session
对于该协议的实现:
1 |
|
接下来的工作就简单了。RequestRetrier
流程其实就是以上个各种方法的使用:
SessionDelegate.urlSession(_:task:didCompleteWithError:)
接收到系统回调。sessionDelegate
通过stateProvider
回调Session.didCompleteTask(_:completion:)
告知Session
任务完成了。此时Session
会根据具体状态决定是否从requestTaskMap
记录中删除 task。sessionDelegate
回调Request.didCompleteTask(_:with:)
。此时Request
会对响应进行验证,之后进入下一步的重试判断阶段。Request.retryOrFinish(error:)
若没有错误产生,直接进入完成阶段。否则进入下一步的重试。Request
会调用delegate(Session).retryResult(for:dueTo:completion:)
获得是否有重试的结果,若需要重试,会调用delegate(Session).retryRequest(_:withDelay:)
进行重试。我们实现的SignRequestInterceptor
也正是在Session.retryResult(for:dueTo:completion:)
方法中获得被调用的机会。
大致流程就是这些,大家可以先对各个参与者有个大致印象,然后跟着流程细看。总体还是比较清晰的。
Alamofire 提供的 RequestInterceptor(s)
框架内部也实现了一些常用的拦截器,如下:
open class Adapter: RequestInterceptor { ... }
:提供闭包风格的请求适配器。open class Retrier: RequestInterceptor { ... }
:提供闭包风格的请求重试器。open class Interceptor: RequestInterceptor { ... }
:拦截器的混合器,可以将多个拦截器包装起来。public class AuthenticationInterceptor<AuthenticatorType>: RequestInterceptor where AuthenticatorType: Authenticator { ... }
:提供授权功能。open class RetryPolicy: RequestInterceptor { ... }
:提供更丰富的重试条件控制,如允许重试的次数,允许重试的请求方法,每次重试过后下次重试的间隔等等等。
AuthenticationInterceptor
和RetryPolicy
简直不要太强!💯,下面会有专门的文章来分析它们,关注期待吧。🤣
总结
今天我们主要梳理里拦截器的工作流程。可以看到,它就是在一个请求事务的前后,给了我们相应的响应机会,其实内容并不复杂。
另外,对应的代码分析,我放在了GitHub上(分支:risk
),希望对你有所帮助。