转载

http://blog.handy.wang/blog/2016/01/29/sdwebimagehuan-cun-zhi-tu-pian-urlbu-bian/

SDWebImage在iOS项目中是一个很常用的开源库,而且众所周知的是,它是基于URL作为Key来实现图片缓存机制的。在90%左右的情况下,
图片与URL是一一对应的,即使服务器修改了图片也会相应的变更URL。但是在少数情况下,服务器修改了图片后不会变更相应的URL,也就是
说图片本身的内容变了然而它的URL没有变化,那么按照对SDWebImage的常规使用方法的话,客户端肯定更新不到同一URL对应到服务器已变
更的图片内容。

基于这一现象,我们来进行分析。

客户端第一次请求图片时,Charles抓包得知response header里有一个名为Last-Modified、数据是时间戳的键值对。

客户端第二次及以后请求图片时,通过Charles抓包发现,服务器返回304 not modified状态,说明服务器在接收客户端请求后通过某种判断逻辑得出结论:“客户端已缓存的图片与服务器图片都是最新的”,那么服务器如何判断的呢?

通过查阅HTTP协议相关的资料得知,与服务器返回的Last-Modified相对应的request header里可以加一个名为If-Modified-Since的key,value即是服务器回传的服务端图片最后被修改的时间,第一次图片请求时If-Modified-Since的值为空,第二次及以后的客户端请求会把服务器回传的Last-Modified值作为If-Modified-Since的值传给服务器,这样服务器每次接收到图片请求时就将If-Modified-Since与Last-Modified进行比较,如果客户端图片已陈旧那么返回状态码200、Last-Modified、图片内容,客户端存储Last-Modified和图片;如果客户端图片是最新的那么返回304 Not Modified、不会返回Last-Modified、图片内容。

关于服务器的比较逻辑,需要强调一下。

经查资料得知,Apache比较时是看If-Modified-Since之后有没有更新图片,Nginx比较时是看If-Modified-Since与Last-Modified是否相等,所以对于Apache服务器环境客户端每次都要严格的存储服务器回传的Last-Modified以便下次请求时作为If-Modified-Since的值传给服务器,对于Nginx服务器环境客户端不必存储服务器回传的Last-Modified,每次请求时只需将图片自身的fileModificationDate作为If-Modified-Since的值传服务器即可。在实际开发中,如果遇到明明传了If-Modified-Since、服务器图片也变更了、但是客户端却请求不到最新的图片的情况时,那么就需要查看一下服务器对这两个时间戳的比较逻辑。

那么,现在我们可以回到SDWebImage上来了。通过查看SDWebImageDownloader的源码得知,它开放了一个headersFilter的block,意在让开发者可以对所有图片请求追加一些额外的header,这正合我意。那么我们就可以在诸如AppDelegate didFinishLaunching的地方追加如下代码:

SDWebImageDownloader *imgDownloader = SDWebImageManager.sharedManager.imageDownloader;
imgDownloader.headersFilter = ^NSDictionary *(NSURL *url, NSDictionary *headers) { NSFileManager *fm = [[NSFileManager alloc] init];
NSString *imgKey = [SDWebImageManager.sharedManager cacheKeyForURL:url];
NSString *imgPath = [SDWebImageManager.sharedManager.imageCache defaultCachePathForKey:imgKey];
NSDictionary *fileAttr = [fm attributesOfItemAtPath:imgPath error:nil]; NSMutableDictionary *mutableHeaders = [headers mutableCopy]; NSDate *lastModifiedDate = nil; if (fileAttr.count > 0) {
if (fileAttr.count > 0) {
lastModifiedDate = (NSDate *)fileAttr[NSFileModificationDate];
} }
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
formatter.dateFormat = @"EEE, dd MMM yyyy HH:mm:ss z"; NSString *lastModifiedStr = [formatter stringFromDate:lastModifiedDate];
lastModifiedStr = lastModifiedStr.length > 0 ? lastModifiedStr : @"";
[mutableHeaders setValue:lastModifiedStr forKey:@"If-Modified-Since"]; return mutableHeaders;
};

然后,加载图片的地方以前怎么写还是怎么写,但别忘了Option是SDWebImageRefreshCached

NSURL *imgURL = [NSURL URLWithString:@"http://handy-img-storage.b0.upaiyun.com/3.jpg"];
[[self imageView] sd_setImageWithURL:imgURL
placeholderImage:nil
options:SDWebImageRefreshCached];

经测试,服务器只修改图片不变更URL的时候,客户端也可以更新到最新的图片。

从以上第一段代码内容可以看出我采用的是与ngix服务器比较逻辑对应的代码,BTW:我测试的服务器是又拍云,说明又拍云的比较逻辑是等与不等的关系判断,不是大小关系的判断。

这里顺便说一下,如果服务器的环境是类似于Apache的比较逻辑时,客户端可以把Last-Modified存放在图片的名称上(这需要修改SDWebImage源码,不建议),或者用一个plist文件存放图片key名称与时间的对应关系(这个不用修改源码)。

OK,到此这次的主题已得到完美解决。

知识扩展

其实,在抓取服务器返回的数据包时,还发现response header中还有一个ETag,与之相对应的request header中可以追加一个
If-None-Match的key,这对header与Last-Modified、If-Modified-Since的作用是相同的,即服务器是否需要返回最新的图片,
当然它们在服务器端的判断逻辑应该是等与不等的判断,Etag在客户端的存储同样可以采用在plist文件中存放图片key名称与Etag的对应
关系。

转载:SDWebImage支持URL不变时更新图片内容的更多相关文章

  1. SDWebImage支持URL不变时更新图片内容

    SDWebImage在iOS项目中是一个很常用的开源库,而且众所周知的是,它是基于URL作为Key来实现图片缓存机制的.在90%左右的情况下, 图片与URL是一一对应的,即使服务器修改了图片也会相应的 ...

  2. PHP+jQuery 长文章分页类 ( 支持 url / ajax 分页方式 )

    /* ******* 环境:Apache2.2.8 ( 2.2.17 ) + PHP5.2.6 ( 5.3.3 ) + MySQL5.0.51b ( 5.5.8 ) + jQuery-1.8 **** ...

  3. 转载文章:Windows Azure 七月份更新:SQL 数据库、流量管理器、自动伸缩、虚拟机

    转载文章:Windows Azure 七月份更新:SQL 数据库.流量管理器.自动伸缩.虚拟机 今天上午,我们发布了一些重大的 Windows Azure 更新.这些新的增强功能包括: · SQL 数 ...

  4. Python 函数运行时更新

    Python 动态修改(运行时更新) 特性 实现函数运行时动态修改(开发的时候,非线上) 支持协程(tornado等) 兼容 python2, python3 安装 pip install realt ...

  5. 转载:Android应用的自动更新模块

    软件的自动更新一般都与Splash界面绑定在一起, 由于需要维护的软件界面很复杂, 一个Activity中嵌入ViewPager, 并且逻辑比较复杂, 索性重新写一个Activity, 现在的软件都很 ...

  6. 应用springMVC时如果配置URL映射时如下配置

    应用springMVC时如果配置URL映射时如下配置 [html] view plaincopy<servlet> <servlet-name>appServlet</s ...

  7. ON DUPLICATE KEY UPDATE重复插入时更新

    mysql当插入重复时更新的方法: 第一种方法: 示例一:插入多条记录 假设有一个主键为 client_id 的 clients 表,可以使用下面的语句: INSERT INTO clients (c ...

  8. ON DUPLICATE KEY UPDATE 当记录不存在时插入,当记录存在时更新

    MySQL 当记录不存在时插入,当记录存在时更新网上基本有三种解决方法.第一种:示例一:插入多条记录假设有一个主键为 client_id 的 clients 表,可以使用下面的语句:INSERTINT ...

  9. mysql ON DUPLICATE KEY UPDATE重复插入时更新

    mysql当插入重复时更新的方法: 第一种方法: 示例一:插入多条记录 假设有一个主键为 client_id 的 clients 表,可以使用下面的语句: INSERT INTO clients (c ...

随机推荐

  1. lua -- 在弹框中显示物品列表

    -- 宝箱打开后,显示里面的物品列表 -- 显示方式是:一个一个显示,每三个一行,一行显示完就移动到下一行, -- 接下来的一样要显示框的中间位置,方便玩家看 function UIBagContro ...

  2. 图灵数学·统计学丛书.PDF(53本全)

    图灵数学·统计学丛书01-概率论及其应用(第1卷·第3版)-[美]William.Feller-人民邮电出版社.pdf 图灵数学·统计学丛书01-金融数学:衍生产品定价引论-[英]M·巴克斯特& ...

  3. tensorflow 笔记7:tf.concat 和 ops中的array_ops.concat

    用于连接两个矩阵: mn = array_ops.concat([a, d], 1) #  按照第二维度相接,shape1 [m,a] shape2 [m,b] ,concat_done shape ...

  4. layui.laytpl中js方法书写及调用:去除html标签

    <script type="text/html" id="conTpl">   {{# var delhtml = function(str) { ...

  5. 【Unity】讯飞语音识别SDK

    1.进入讯飞官网,注册帐号,进入控制台,创建新应用UnityXunfeiDemo,平台选Android.在当前应用这点下载SDK,添加AI能力(添加新服务),选择语音听写,即可下载安卓SDK(下称讯飞 ...

  6. (原)java 向上转型中,任何域的访问操作都是由编译器解析,不是多态

    最近在向java发力,学习学习了下.看到了多态这一节,书中有个比较好的例子,所以就准备写下来,记录下来: package dynamic_binding01; public class dynamic ...

  7. 记一个神奇的WAS问题:sibuswsgw-sibuswsgw_console.jar invalid LOC header (bad signature) 分类: WebSphere 2015-08-06 23:21 9人阅读 评论(0) 收藏

    今天晚上,出现了一个神奇的WAS问题,详细问题异常信息如下: [15-8-6 22:13:29:146 CST] 00000013 ApplicationMg A WSVR0203I: 应用程序:is ...

  8. DES ECB 模式 JAVA PHP C# 实现 加密 解密 兼容

    版本一: JAVA: import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sun.misc.BASE64Decoder; i ...

  9. Linux学习之---Xshell

    经过两周的断断续续的学习,终于把慕课网上tony老师的<Linux网络管理>基础知识学完.tony老师讲课风趣幽默,深入浅出,为老师打call!! 课程地址:https://www.imo ...

  10. G - SDOI

    The Annual National Olympic of Information(NOI) will be held.The province of Shandong hold a Select( ...