用NSURLSession
请求数据时,NSURLCache
会把request对应的response和data缓存下来,下一次发起同样请求时可以从缓存中读取。我们可以设置NSURLSession
的requestCachePolicy
或者NSMutableURLRequest
的cachePolicy
来控制缓存的读取。具体的流程如下图所示:

NSURLRequestCachePolicy
-
NSURLRequestUseProtocolCachePolicy
: 如果缓存不存在,直接从服务端获取。如果缓存存在,会根据response中的Cache-Control字段判断下一步操作; -
NSURLRequestReloadIgnoringLocalCacheData
、NSURLRequestReloadIgnoringCacheData
: 不使用缓存,直接请求原始数据; -
NSURLRequestReturnCacheDataElseLoad
: 若没有缓存则从服务器请求 若有缓存则无论缓存是否过期都直接返回; -
NSURLRequestReturnCacheDataDontLoad
: 若没有缓存则返回错误 若有缓存则无论缓存是否过期都直接返回; -
NSURLRequestReloadRevalidatingCacheData
:缓存数据必须得得到服务端确认有效才使用;
操作一:现在来请求一张图片数据,为了能让Wireshark抓到包,我把https改成了http:
Wireshark拦截手机端的具体操作:NSURLCache缓存流程与实例分析
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://hbimg.huabanimg.com/dd2b301968eff7750bb000166771aff9e14d149ab524-ByybtO_fw658"]];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
[dataTask resume];
WireShark抓包结果:

可以看到服务端返回了200,在
NSURLSessionDataDelegate
的didReceiveResponse
也可以看到response的statusCode是200。这时候清除Wireshark的包,我们在手机端重复发这个请求,会发现并没有真正发起网络请求,是因为NSURLCache已经把我们之前拿到的结果缓存下来了,而且我们没有在头部设置过期的相关数据,所有它认为缓存的数据没有过期,在didReceiveResponse中拿到的statusCode还是200。
在截图中可以看到返回的头部有两个信息:
ETag: "5c4fcf3e71aa437a52cd1f09731a81d0"\r\n
Last-Modified: Tue, 31 Dec 2019 07:37:27 GMT\r\n
如果我们发请求的时候在头部带上这两个信息,服务器会判断资源是否修改,如果没有修改则只返回304头部,不再返回数据,这时手机端会取缓存好的数据返回来。
操作二:我们现在在头部加上这两个信息,再发送请求:
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://hbimg.huabanimg.com/dd2b301968eff7750bb000166771aff9e14d149ab524-ByybtO_fw658"]];
NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
if (cachedResponse) {
NSDictionary *responseHeaders = [((NSHTTPURLResponse *)cachedResponse.response) allHeaderFields];
[request setValue:[responseHeaders objectForKey:@"Etag"] forHTTPHeaderField:@"If-None-Match"];
[request setValue:[responseHeaders objectForKey:@"Last-Modified"] forHTTPHeaderField:@"If-Modified-Since"];
}
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
[dataTask resume];

可以看到服务器返回的是304,但没有返回数据。可是我们在didReceiveResponse中拿到的statusCode还是200,而且能拿到data,这是从缓存中返回的。
操作三:再把这两个字段去掉,修改request的缓存策略:
request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
这时候可以发现不管发多少次请求,都是真正发起网络请求的,因为设置忽略了本地缓存。
操作四:加上忽略缓存的配置后,我们再次加上Last-Modified
和If-Modified-Since
这两个字段,会发现服务器给我们返回304,而且在didReceiveResponse中拿到的也是304,而且没有data,因为我们设置了忽略缓存。
WKWebView是不使用NSURLCache的。
网友评论