当WebLink找不到时,UIWebView不会去didFailLoadWithError?
我使用UIWebView
从webLink
和UIWebViewDelegate
加载web来控制错误状态:
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:webLink]]]; - (void)webViewDidStartLoad:(UIWebView *)webView{ NSLog(@"START LOAD"); } - (void)webViewDidFinishLoad:(UIWebView *)webView{ NSLog(@"FINISH LOAD"); } - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error{ NSLog(@"ERROR : %@",error); }
但是,当webLink
没有find,它不会去didFailLoadWithError
,它会去startLoad
和didFinishLoad
。 webLink
未find时如何处理? 请帮忙!
不幸的是,404(或类似的代码)不被UIWebView
视为错误,因为收到了HTML响应。 更糟糕的是, UIWebView
不会为我们捕获响应代码,所以您必须通过NSURLConnection
手动执行此操作。 这里有一个方法来处理它:
@interface ViewController () <UIWebViewDelegate, NSURLConnectionDataDelegate> @property (nonatomic) BOOL validatedRequest; @property (nonatomic, strong) NSURL *originalUrl; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // since `shouldStartLoadWithRequest` only validates when a user clicks on a link, we'll bypass that // here and go right to the `NSURLConnection`, which will validate the request, and if good, it will // load the web view for us. self.originalUrl = [NSURL URLWithString:@"http://www.stackoverflow.com"]; NSURLRequest *request = [NSURLRequest requestWithURL:self.originalUrl]; [NSURLConnection connectionWithRequest:request delegate:self]; } #pragma mark - UIWebViewDelegate // you will see this called for 404 errors - (void)webViewDidFinishLoad:(UIWebView *)webView { self.validatedRequest = NO; // reset this for the next link the user clicks on } // you will not see this called for 404 errors - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { NSLog(@"%s error=%@", __FUNCTION__, error); } // this is where you could, intercept HTML requests and route them through // NSURLConnection, to see if the server responds successfully. - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { // we're only validating links we click on; if we validated that successfully, though, let's just go open it // nb: we're only validating links we click on because some sites initiate additional html requests of // their own, and don't want to get involved in mediating each and every server request; we're only // going to concern ourselves with those links the user clicks on. if (self.validatedRequest || navigationType != UIWebViewNavigationTypeLinkClicked) return YES; // if user clicked on a link and we haven't validated it yet, let's do so self.originalUrl = request.URL; [NSURLConnection connectionWithRequest:request delegate:self]; // and if we're validating, don't bother to have the web view load it yet ... // the `didReceiveResponse` will do that for us once the connection has been validated return NO; } #pragma mark - NSURLConnectionDataDelegate method // This code inspired by http://www.ardalahmet.com/2011/08/18/how-to-detect-and-handle-http-status-codes-in-uiwebviews/ // Given that some ISPs do redirects that one might otherwise prefer to see handled as errors, I'm also checking // to see if the original URL's host matches the response's URL. This logic may be too restrictive (some valid redirects // will be rejected, such as www.adobephotoshop.com which redirects you to www.adobe.com), but does capture the ISP // redirect problem I am concerned about. - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { NSString *originalUrlHostName = self.originalUrl.host; NSString *responseUrlHostName = response.URL.host; NSRange originalInResponse = [responseUrlHostName rangeOfString:originalUrlHostName]; // handle where we went to "apple.com" and got redirected to "www.apple.com" NSRange responseInOriginal = [originalUrlHostName rangeOfString:responseUrlHostName]; // handle where we went to "www.stackoverflow.com" and got redirected to "stackoverflow.com" if (originalInResponse.location == NSNotFound && responseInOriginal.location == NSNotFound) { NSLog(@"%s you were redirected from %@ to %@", __FUNCTION__, self.originalUrl.absoluteString, response.URL.absoluteString); } if ([response isKindOfClass:[NSHTTPURLResponse class]]) { NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode]; if (statusCode < 200 || statusCode >= 300) { NSLog(@"%s request to %@ failed with statusCode=%d", __FUNCTION__, response.URL.absoluteString, statusCode); } else { self.validatedRequest = YES; [self.webView loadRequest:connection.originalRequest]; } } [connection cancel]; } @end
请注意,在我的实现中,我不仅要检查状态码,还要检查redirect(您可能会也可能不想这样做)。 我这样做是因为一些ISP拦截HTTP请求,如果没有find目标站点,redirect到他们自己的search网页(我知道我的ISP正在检查我search的每个网站,我觉得有点令人毛骨悚然)。 如果你正在处理通过wifi连接的iPhone,你必须处理这些变幻莫测的事情。
所以,例如,我上面的代码正在search“ http://www.applecom/pages ”(我故意省略了“.com”的时间段,这会使DNS查找失败),但是对于我的ISP, Verizon截获了请求,并通过HTTP连接redirect到他们自己的search页面,因此我的应用程序正在报告:
2013-01-21 23:14:21.896 webtest [24198:c07] – [ViewController connection:didReceiveResponse:]你被从http://www.applecom/pagesredirect到http://search.dnsassist.verizon.net/ assist.php?URL = http://www.applecom
你可能想要考虑什么样的redirect是可以接受的(例如,如果你去“www.adobephotoshop.com”,它将你redirect到“www.adobe.com”),什么样的不是(例如,如果我去“www.applecom”,它将我redirect到“search.dnsassist.verizon.net”。我可能担心一个相当狭窄的问题(这会影响我,因为我的ISP),但是这是一个需要考虑的事情。