阅读 4

iOS 开发实战小知识——NSURLRequestCachePolicy

前言

好久都没写文章了,总觉得没什么可写的,没有什么新的、难的技术来写。 突然转念一想,这违背了我写文章的初衷。我写文章的目的是:记录一些开发中遇到的问题,方便自己或他人后面查找填坑。

问题

测试反馈一个问题,说是进入到商品详情页,抓不到接口请求。

我第一反应:不可能,我这进入到商品详情页肯定会请求接口啊,不请求接口没有数据返回,怎么显示界面出来。 一定是你抓包的姿势不对。。 你换个姿势试试?

到晚上快下班的时候,测试还说抓不到,那句怼死你不负责经典话就出来了:** Android的可以抓到,就你iOS抓不到 **。。。 我无言以对。

只能在自己找找原因。我说我回去在看看,看看可能什么原因哈。 测试一脸不情愿的边走边说:“你是不是做了什么缓存啊? ”缓存啊?存啊? 啊??? 我说没有,缓存很难做的,我没有处理过。

追究

之前一直都可以的,怎么突然就不行了呢? 我没做什么修改啊。做数据缓存是不可能的,不可能去缓存商详页等那么多界面的接口哇。

最近除了后台有增加CDN没有别的啊。 咦 后台加了CDN。。为了应对双十一大促活动,后台接入了CDN缓存策略,为了减少服务器的压力。

cdn缓存的作用是调接口时,不用回源到服务器,在cdn边缘节点就近返回

是不是后台加了CDN导致,之前项目貌似也遇到过类似的问题呢。

原理

当接口加了CDN之后,会在请求头里返回一个Cache-Control 字段。

接口返回请求头.png

Cache-Control: max-age=秒 后面是缓存策略

public 所有内容都将被缓存
private 内容只缓存到私有缓存中
no-cache 所有内容都不会被缓存
no-store 所有内容都不会被缓存到缓存或 Internet 临时文件中

就是因为接口加了CDN,请求头里返回了Cache-Control有值,在配合苹果网络请求,才没有去请求接口。

NSURLRequestCachePolicy 请求缓存策略:

 NSURLRequestUseProtocolCachePolicy = 0,  //默认 使用缓存
 NSURLRequestReloadIgnoringLocalCacheData = 1, //忽略缓存,每次都请求新的数据
 NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4, // Unimplemented
 NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData,
 NSURLRequestReturnCacheDataElseLoad = 2, //如果在之前的网络请求中,我们获取了Cache的Response,那么本次请求同样的接口,就直接从Cache中去抓。反之,从服务器上去获取,并在本地cache起来。
 NSURLRequestReturnCacheDataDontLoad = 3, //只从缓存中获取cached response而不从服务器获取。实属离线版本。
 NSURLRequestReloadRevalidatingCacheData = 5, // Unimplemented
复制代码
原因:

我们如果没有特别处理,都是使用默认请求缓存策略。不管是在性能还是交互都会好些,苹果也推荐使用这种。

默认的ProtocolCachePolicy机制:

1、如果一个Request的NSCachedURLResponse不存在,就去请求网络。

2、如果一个Request的NSCachedURLResponse存在,就去检查response去决定是否需要刷新。检查Response header的Cache-Control字段是否含有must-revalidated字段(HTTP1.1所带)。

3、如果包含must-revalidated字段,就通过HEAD方法请求服务器,判断Response头是否有更新,如果有,则去拉数据下来。如果没有,则使用Cache资源。

4、如果不包含must-revalidated字段,就看看Cache-Control是否包含其他字段,比如max-age等等看看是否过期,如果过期,继续用HEAD去检查Response头,是否为最新数据,如果有则去请求服务器,反之取cache。如果没有过期,则直接取cache。

然后通用HTTP的缓存策略:

HTTP缓存策略中,我们从服务器获取Response后,可以找到(如果有)Response中包含Etag或则Last-Modified字段。当我们做第二次重复请求的时候,可以从CachedURLResponse取出来,把相应字段拼接在HTTPRequestHeader中,然后发送请求,服务端收到后,如果客户端的资源是最新的,那么就会返回304为Response,而不返回任何内容。反之,如果客户端资源落后了,则直接返回200,并返回Data给客户端。

正式由于接口加了CDN,客户端使用了默认的缓存方式。第二次在进入到商品详情页的时候,就是抓不到请求数据,直接使用了缓存数据。

修复

我们的需求是每次进入到商详页都要请求最新的数据。而接口必须要加CDN,客户端就应该每次都调接口,接口响应速度由服务端来处理。只能客户端修改缓存策略。将request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData 设置成这个。

或者设置请求头[self.requestSerializer setValue:@"no-cache" forHTTPHeaderField:@"Cache-Control"];

后续——为什么会出现这个情况呢?

后台为了减小服务器的压力,不能频繁的请求。所以加了CDN策略。 接口数据越稳定,Cache-Control 设置的时间就越久。(比如分类列表、商详页数据基本不会频繁变化) 但是这个需求要求,每次都请求最新的数据,因为商品数据可能实时变化,这确实有些矛盾了。 但是没办法,只能这么做。 后台已经说了:接口响应速度他们去优化,你们只管每次都来请求数据就好。

参考文章

基于NSURLCache的缓存实现

关注下面的标签,发现更多相似文章
评论