由于后台更新了一个网页,但iOS这边显示的还是旧内容。此现象 —— 网页的缓存
typedef NS_ENUM(NSUInteger, NSURLRequestCachePolicy)
{
NSURLRequestUseProtocolCachePolicy = 0, // 默认策略,具体的缓存逻辑和协议的声明有关,如果协议没有声明,不需要每次重新验证cache。
NSURLRequestReloadIgnoringLocalCacheData = 1, // 忽略本地缓存,直接从后台请求数据
NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4, // 系统未实现,忽略本地缓存数据、代理和其他中介的缓存,直接从后台请求数据
NSURLRequestReturnCacheDataElseLoad = 2, // // 优先从本地拿数据,且忽略请求生命时长和过期时间。但是如果没有本地cache,则请求源数据
NSURLRequestReturnCacheDataDontLoad = 3, //只从本地拿数据
NSURLRequestReloadRevalidatingCacheData = 5, // 未实现 从原始地址确认缓存数据的合法性后,缓存数据就可以使用,否则从原始地址加载。
};
这里我们需要注意的是 NSURLRequestReloadIgnoringLocalCacheData
和 NSURLRequestReturnCacheDataElseLoad
。NSURLRequestReloadIgnoringLocalCacheData:
忽略缓存,直接取网络。NSURLRequestReturnCacheDataElseLoad:
先读取缓存,没有缓存则取网络。
1、使用 NSURLRequestReloadIgnoringLocalCacheData 来实时加载网页
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:self.urlString] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:20];
[_webView loadRequest:request];
2、通过 NSHTTPURLResponse 中的 Last-Modified 或者 Etags 来判断当前html是否是最新的网页(此方法没有亲测)
表示文件的最后修改时间,例如"Fri, 26 Oct 2018 03:17:23 GMT"
,当请求 html 时,我们会向服务器发送 If-Modified-Since
报头,查看文件是否被修改,如果没有被修改,则 HTTP 返回303状态码,如果会修改了返回200。
客户端通过 If-None-Match 这个条件判断请求来验证资源是否修改。服务器判断发送过来的 Etag 和计算出来的 Etag 匹配,因此 If-None-Match 为False,不返回200,返回304,客户端继续使用本地缓存。
具体可以看这篇HTTP缓存控制小结
先查看打印
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:self.urlString]
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:20];
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
NSLog(@"httpResponse == %@", httpResponse);
}] resume];
可以看到
httpResponse == { URL: ---} {
Status Code: 304,
Headers {
Date = (
"Sat, 27 Oct 2018 01:19:36 GMT"
);
Etag = (
"\"5bb086b4-2bd\""
);
"Last-Modified" = (
"Sun, 30 Sep 2018 08:17:56 GMT"
);
Server = (
Tengine
);
} }
想要的参数都在里面。
具体实现
_webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, WY_ScreenWidth, WY_ScreenHeight - WY_NavBar_H + WY_SAFE_TOP) configuration:configuration];
_webView.navigationDelegate = self;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:self.urlString]
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:20];
NSDictionary *cachedHeaders = [[NSUserDefaults standardUserDefaults] objectForKey:self.urlString];
//设置request headers (带上上次的请求头下面两参数一种就可以,也可以两个都带上)
if (cachedHeaders) {
NSString *etag = [cachedHeaders objectForKey:@"Etag"];
if (etag) {
[request setValue:etag forHTTPHeaderField:@"If-None-Match"];
}
NSString *lastModified = [cachedHeaders objectForKey:@"Last-Modified"];
if (lastModified) {
[request setValue:lastModified forHTTPHeaderField:@"If-Modified-Since"];
}
}
[_webView loadRequest:request];
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
NSLog(@"httpResponse == %@", httpResponse);
// 根据statusCode设置缓存策略
if (httpResponse.statusCode == 304 || httpResponse.statusCode == 0) {
[request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
} else {
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
// 保存当前的NSHTTPURLResponse
[WY_UserDefaults setObject:httpResponse.allHeaderFields forKey:self.urlString];
}
// 重新刷新
dispatch_async(dispatch_get_main_queue(), ^{
[_webView reload];
});
}] resume];
这样就达到了缓存的目的。