iOS 7 UIWebView 304缓存bug,空白页面

时间:2014-02-14 00:00:40

标签: ios iphone objective-c ios7 uiwebview

我在我的应用中发现了一个有UIWebView的问题。 iOS 7缓存空白主体304响应,导致在用户刷新UIWebView时显示空白页面。这不是很好的用户体验,我试图弄清楚如何在iOS端解决这个问题,因为我无法控制Amazon S3如何响应标头(这是我用于资源托管的人)。

这些人发现了这个错误的更多细节:http://tech.vg.no/2013/10/02/ios7-bug-shows-white-page-when-getting-304-not-modified-from-server/

我很感激能为我如何在应用程序端而不是服务器端解决此问题提供任何帮助。

谢谢。

更新:使用赏金的建议作为指导来修复此错误:

@property (nonatomic, strong) NSString *lastURL;

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

    if ([self.webView stringByEvaluatingJavaScriptFromString:@"document.body.innerHTML"].length < 1)
    {
        NSLog(@"Reconstructing request...");
        NSString *uniqueURL = [NSString stringWithFormat:@"%@?t=%@", self.lastURL, [[NSProcessInfo processInfo] globallyUniqueString]];
        [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:uniqueURL] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:5.0]];
    }
}

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    self.lastURL = [request.URL absoluteString];
    return YES;
}

3 个答案:

答案 0 :(得分:2)

您可以实现NSURLProtocol,然后在+canonicalRequestForRequest:中修改请求以覆盖缓存策略。

这将适用于所有请求,包括Web视图中的静态资源,这些资源通常不会与公共API委托进行协商。

这非常强大,而且很容易实现。

以下是更多信息: http://nshipster.com/nsurlprotocol/

参考: https://developer.apple.com/library/ios/documentation/cocoa/reference/foundation/Classes/NSURLProtocol_Class/Reference/Reference.html


以下是一个例子:

@interface NoCacheProtocol : NSURLProtocol

@end

@implementation NoCacheProtocol

+ (void)load
{
    [NSURLProtocol registerClass:[NoCacheProtocol class]];
}

+ (BOOL)canInitWithRequest:(NSURLRequest*)theRequest
{
    if ([NSURLProtocol propertyForKey:@“ProtocolRequest” inRequest:theRequest] == nil) {
        return YES;
    }
    return NO;
}

+ (NSURLRequest*)canonicalRequestForRequest:(NSURLRequest*)theRequest
{
    NSMutableURLRequest* request = [theRequest mutableCopy];
    [request setCachePolicy: NSURLRequestReloadIgnoringLocalCacheData];
    //Prevent infinite recursion:
    [NSURLProtocol setProperty:@YES forKey:@"ProtocolRequest" inRequest:request];

    return request;
}

- (void)startLoading
{
    //This is an example and very simple load..

    [NSURLConnection sendAsynchronousRequest:self.request queue:[NSOperationQueue currentQueue] completionHandler:^ (NSURLResponse* response, NSData* data, NSError* error) {
        [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
        [[self client] URLProtocol:self didLoadData:data];
        [[self client] URLProtocolDidFinishLoading:self];
    }];
}

- (void)stopLoading
{
    NSLog(@"something went wrong!");
}

@end

答案 1 :(得分:1)

由于其他问题是每次都使用NSURLConnection,这似乎有点开销: 为什么不在页面加载(完整或不完整)之后执行一个小的javascript,它可以告诉你页面是否实际显示?查询应该存在的标记(比如你的内容div)并使用

返回true / false
[UIWebView stringByEvaluatingJavaScriptFromString:@"document.getElementById('adcHeader')!=null"]

然后,如果返回false,您可以使用您自己描述的缓存破坏技术手动重新加载URL:

NSString *uniqueURL = [NSString stringWithFormat:@"%@?t=%d", self.url, [[NSDate date] timeIntervalSince1970]]; 
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:uniqueURL] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:5.0]];

[编辑]

根据评论中的讨论和其他一些答案,我认为您可能拥有手动更改NSURLCache的最佳解决方案。

从我收集的内容来看,您主要是尝试解决重新加载/重新设置方案。在这种情况下,查询NSURLCache是否存在正确的响应,如果没有,则在重新加载UIWebView之前删除storedvalue。

[编辑2]

根据您的新结果,尝试在NSURLCache损坏后删除它:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache]cachedResponseForRequest:request];

  if (cachedResponse != nil && [[cachedResponse data] length] > 0)
  {
      NSLog(@"%@",cachedResponse.response);
  } else {
    [[NSURLCache sharedURLCache] removeCachedResponseForRequest:request];
  }

  return YES;
}

如果缓存再次无效,我们可能需要优化检查,但理论上这应该可以做到!

答案 2 :(得分:0)

NSURL *URL = [NSURL URLWithString:@"http://mywebsite.com"];    
NSURLRequest *request = [NSURLRequest requestWithURL:URL
                                             cachePolicy:NSURLRequestReloadIgnoringCacheData 
                                         timeoutInterval:30.0];

[myWebView loadRequest: request];

创建NSURLRequest实例时,可以设置缓存策略。 希望它有效!