AFNetworking 2.0 - 强制缓存

7
是否可能在响应中既不包含 Expires 也不包含 Cache-Control: max-age 的情况下强制响应缓存?
我遇到了这篇文章,但不幸的是,我的 AFHTTPSessionManager 子类中从未调用过 URLSession:dataTask:willCacheResponse:completionHandler:
任何帮助都将不胜感激。

你可以使用 NSMutableURLRequestcachePolicy 属性。 - fluidsonic
1个回答

6
您可以通过实现自己的NSURLProtocol来强制缓存,而不遵循标准的HTTP缓存规则。这里有一个完整的教程,它使用Core Data持久化数据,但基本步骤如下:
  • 子类化NSURLProtocol
  • 使用+registerClass:注册您的子类
  • 如果这是您第一次看到request,则在您的+canInitWithRequest:方法中返回YES,否则返回NO

现在您有两个选择:

  1. 实现自己的缓存存储(在这种情况下,请遵循上面链接的教程)
  2. 注入您希望URL加载系统遵循的缓存控制头

假设您想要#2,那么请在您的协议子类中覆盖connection:didReceiveResponse:以创建一个具有您想要模拟的缓存控制头的响应:

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response {
    // Create a dictionary with the headers you want
    NSMutableDictionary *newHeaders = [response.allHeaderFields mutableCopy];
    newHeaders[@"Cache-Control"] = @"no-transform,public,max-age=300,s-maxage=900";

    // Create a new response
    NSHTTPURLResponse *newResponse = [[NSHTTPURLResponse alloc] initWithURL:response.URL
                                                                 statusCode:response.statusCode
                                                                HTTPVersion:@"HTTP/1.1"
                                                               headerFields:newHeaders];


    [self.client URLProtocol:self
          didReceiveResponse:newResponse
          cacheStoragePolicy:NSURLCacheStorageAllowed];
}

这将导致响应被缓存,就像服务器提供了这些标头一样。
仅适用于URL会话,您需要设置会话配置的protocolClasses。由于您正在使用AFNetworking,因此看起来像这样:

对于URL会话,您需要设置会话配置的protocolClasses。由于您正在使用AFNetworking,所以代码如下:

[AFHTTPSessionManager sharedManager].session.configuration.protocolClasses = @[[MyURLProtocol class]]

有一些注意事项,所以请确保您阅读protocolClasses文档


一些注意事项:

  • 如果有办法通过让您的服务器发送适当的标头来修复此问题,请务必这样做。
  • 为简洁起见,我硬编码了“HTTP / 1.1”,但从技术上讲,您应该从响应中提取它。
  • AFNetworking使用标准的URL加载系统,与此问题大多无关。

@BenW 很酷,如果你有任何问题,请告诉我。 - Aaron Brager
我应该提到,我在didFinishLoadingWithOptions中首先注册它,所以它应该具有优先权,而且我找不到任何其他已注册的URL协议。 - Ben W
@BenW canInitWithRequest: 被调用了吗?如果是的话,并且你在其中返回了 YES,那么应该调用 startLoading。如果没有被调用,你是否在发出任何请求之前使用 registerClass: 注册了子类? - Aaron Brager
@BenW 另外,我刚刚意识到你正在使用URL会话。如果你正在使用NSURLSessionTask,你可能需要从canInitWithTask:返回YES。 - Aaron Brager
这篇链接的文章非常棒,这个答案也是一样,谢谢! - SimplGy
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接