网络层架构

文章看自这里

网络层设计需要注意

1. 以什么样的方式将数据交付给业务层

Delegate block notification

尽量不要使用notification,这要会导致可能的跨层访问导致耦合性增加;notification的一对多关系,导致问题难以追踪

block比较难追踪、维护;block会延长对象的生命周期;

在离散场景下,因为每次回调时做的任务,在每次回调时都是一致的,因此不要用block,使用delegate最好
在集约型调用时,因为每次请求类型都不一样,回调做的业务也不一致,因此使用block较好

在网络请求和网络层接受请求地方,采用block没问题,但是在获得数据交给业务方时,最好还是通过delegate去通知业务方,因为使用block的话 会导致调用请求的逻辑和获得结果的处理逻辑在同一个地方,代码变长,同时包含调用前和调用后的两部分逻辑,一次使用delegate,请求API地方只写请求的逻辑,在回调地方 只写回调的逻辑

2.交付什么样的数给业务层

不要交付直接转换好的对象模型给业务层,可以交付json或者NSDictionary或者array,然后业务层通过特定的工具类转换为自己需要的数据(这个工具类可能是遵循了同一个协议的很多类,每个类有自己的转换方法,以及转换结果)

如果直接下发模型给业务层,那么在API请求层可能会有很多转换性能消耗,而且需要引入很多模型类,导致维护灾难

使用统一的工具类转换: 1. 可以使转换的逻辑集中,2. 将数据网络请求的数据直接转换为我们View需要展示的方便的数据,一步到位 3. 可以将业务数据和业务隔离,如果业务逻辑有修改,直接修改或者替换这个工具类即可,而UI有修改时,也不影响该转换工具类

转化出来的数据是直接可用的数据,不限定于dictionary或者model,也可以是view或者tableCell等

3.调用API应该是集约型还是离散型

集约型: 所有api调用的是同一个类
离散型: 每一个请求api对应初始化一个请求类的对象

推荐离散型原因:

  1. 可以方便做到正在进行的请求的取消
  2. 离散型可以针对不同的请求做不同的处理方式
  3. 当请求的着陆点消失时,离散型可以直接在请求类中感知并取消请求
    如果是离散型的API调用,取消请求的代码写到APIManager里面就可以了,然后随着ViewController的回收进程,APIManager也会被跟着回收,这部分代码就得到了调用的机会。
  4. 离散型的请求可以给业务方提供更灵活性

综上,关于集约型的API调用和离散型的API调用,我倾向于这样:对外提供一个BaseAPIManager来给业务方做派生,在BaseManager里面采用集约化的手段组装请求,放飞请求,然而业务方调用API的时候,则是以离散的API调用方式来调用。如果你的App只提供了集约化的方式,而没有离散方式的通道,那么我建议你再封装一层,便于业务方使用离散的API调用方式来放飞请求。

关于集约型的API调用和离散型的API调用,我倾向于这样:对外提供一个BaseAPIManager来给业务方做派生,在BaseManager里面采用集约化的手段组装请求,放飞请求,然而业务方调用API的时候,则是以离散的API调用方式来调用。

当我们不得已要实现继承时,最好使用协议方式来规范子类的重载方法,使用IOP方式来限制派生类的重载

总结

  1. 使用delegate来做数据对接,仅在必要时采用Notification来做跨层访问
  2. 提供reformer机制来处理网络层反馈的数据,这个机制很重要,好处极多
  3. 网络层上部分使用离散型设计,下部分使用集约型设计
  4. 设计合理的继承机制,让派生出来的APIManager受到限制,避免混乱

网络层的安全

网络层优化方案

优化入手切点:

  1. 针对链路建立环节的优化
  2. 针对链路传输数据量的优化
  3. 针对链路复用的优化

针对链路建立环节的优化

请求建立的步骤:

  1. 发起请求
  2. DNS解析得到域名
  3. 根据IP进行3次或者4次(HTTPS)握手

优化方案1.1: 缓存一些时效性比较长数据,减少请求发起的次数,将把API名字和参数拼成一个字符串然后取MD5作为key,存储对应数据; 清除数据策略:超时清理或者缓存数据过大清理,可以根据APP的操作日志决定;缓存可以存储在内存中,或者磁盘上
优化方案1.2: 减少请求发起的次数;1)比如多次下拉刷新,在一次请求没落地前剩下的没必要继续请求发送了 2)而类似条件筛选的,就可以取消前面的发送的请求 3)对于某些请求,没必要频繁发送的,可以先在本地记录,等数据满多少条后,上传数据;app每次启动时,上传上次的一流数据

优化方案2.1: 因为移动端的信号源常变,因此DNS链路的缓存经常变化,导致缓存的作用一般,另外因为很多应用app网络请求操作,属于你的app的DNS缓存很快被其他应用使用、覆盖,因此在解析DNS时,会耗费时间,优化方案就是:直接使用ip请求

对于建立链接时候的第三步,国内的网络环境分北网通南电信(当然实际情况更复杂,这里随便说说),不同服务商之间的连接,延时是很大的,我们需要想办法让用户在最适合他的IP上给他提供服务,那么就针对我们绕过DNS服务的手段有一个额外要求:尽可能不要让用户使用对他来说很慢的IP。

所以综上所述,方案就应该是这样:本地有一份IP列表,这些IP是所有提供API的服务器的IP,每次应用启动的时候,针对这个列表里的所有IP取ping延时时间,然后取延时时间最小的那个IP作为今后发起请求的IP地址。

针对建立连接的优化手段其实是跟DNS域名解析的优化手段是一样的。不过这需要你的服务器提供
服务的网络情况要多,一般现在的服务器都是双网卡,电信和网通。由于中国特色的互联网ISP分
布,南北网络之间存在瓶颈,而我们App针对链接的优化手段主要就是着手于如何减轻这个瓶颈对
App产生的影响,所以需要维护一个IP列表,这样就能就近连接了,就起到了优化的效果。

我们一般都是在应用启动的时候获得本地列表中所有IP的ping值,然后通过NSURLProtocol的
手段将URL中的HOST修改为我们找到的最快的IP。另外,这个本地IP列表也会需要通过一个API
来维护,一般是每天第一次启动的时候读一次API,然后更新到本地。

针对链接复用的优化

自己的一些思考

  1. 转化网络层下发数据的一些思考:
    业务层通过特定的工具类转换为自己需要的数据(这个工具类可能是遵循了同一个协议的很多类,每个类有自己的转换方法,以及转换结果)

  2. 使用离散型请求,关于多模块共享数据

    我们可以使用离散型请求,在业务层获取到数据后,如果该数据需要共享,则可以业务层告诉一个共享模块(单例模块),将此数据存储(此共享模块数据Model层,提供数据的存。取、删、该等功能)