UIWebView не перейти к didFailLoadWithError, когда webLink не найден?
Я использую UIWebView
загрузить веб из webLink
а также UIWebViewDelegate
контролировать состояние ошибки:
[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
не найден, это НЕ перейти к didFailLoadWithError
хожу startLoad
а также didFinishLoad
, Как пройти ситуацию, когда webLink
не найдено? Пожалуйста помоги!
1 ответ
К сожалению, 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.stackru.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.stackru.com" and got redirected to "stackru.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
Обратите внимание, что в моей реализации я не только проверяю коды состояния, но я также проверяю перенаправления (что вы можете или не можете делать). Я делаю это потому, что некоторые интернет-провайдеры перехватывают HTTP-запросы и, если целевой сайт не найден, перенаправляют вас на свою собственную поисковую веб-страницу (что, я думаю, немного жутко, зная, что мой интернет-провайдер проверяет каждый веб-сайт, который я ищу). И если вы имеете дело с iPhone, которые подключаются через Wi-Fi, вы должны иметь дело с этими капризами.
Так, например, мой код выше ищет " http://www.applecom/pages" (в котором я намеренно пропустил период ".com", который должен провалиться при поиске DNS), но для которого мой провайдер, Verizon перехватил запрос и перенаправил по HTTP-соединению на собственную страницу поиска, и мое приложение сообщает:
2013-01-21 23: 14: 21.896 веб-тест [24198:c07] -[Соединение ViewController:didReceiveResponse:] вы были перенаправлены с http://www.applecom/pages на http://search.dnsassist.verizon.net/assist.php?url=www.applecom
Возможно, вы захотите подумать о том, какие перенаправления являются допустимыми (например, если вы переходите на "www.adobephotoshop.com" и он перенаправляет вас на "www.adobe.com"), а какие нет (например, если я перейдите на "www.applecom", и он перенаправит меня на "search.dnsassist.verizon.net". Возможно, меня беспокоит довольно узкая проблема (которая затрагивает меня из-за моего интернет-провайдера), но об этом стоит подумать.