दुर्भाग्यवश, 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
ध्यान दें,, मैं सिर्फ स्थिति कोड के लिए जाँच नहीं कर रहा हूँ, लेकिन मैं यह भी रीडायरेक्ट के लिए जाँच कर रहा हूँ (जो आप या नहीं करने के लिए चाहते हो सकता है हो सकता है): यहाँ इससे निपटने के लिए एक ही रास्ता है । मैं ऐसा इसलिए करता हूं क्योंकि कुछ आईएसपी के अवरोध HTTP अनुरोध, और यदि गंतव्य साइट नहीं मिली है, तो आपको अपने स्वयं के खोज वेब पेज पर रीडायरेक्ट करें (जो मुझे लगता है कि यह जानकर थोड़ा डरावना है कि मेरा आईएसपी हर वेब साइट की तलाश कर रहा है)। और यदि आप वाईफाई के माध्यम से कनेक्ट होने वाले आईफ़ोन से निपट रहे हैं, तो आपको इन अनियमितताओं से निपटना होगा।
तो, उदाहरण के लिए, मेरे कोड ऊपर "http://www.applecom/pages" के लिए खोज कर रहा है (जिसमें मैं जानबूझ कर ".com" है, जो DNS लुकअप विफल की अवधि छोड़े गए), लेकिन जिसके लिए मेरी आईएसपी, वेरिज़ोन अनुरोध को रोका और अपने स्वयं के खोज पृष्ठ पर HTTP कनेक्शन द्वारा निर्देशित कर दिये और इस प्रकार, मेरे ऐप रिपोर्ट कर रहा है:
2013-01-21 23: 14: 21.896 webtest [24198: C07] - [ViewController कनेक्शन: didReceiveResponse :] आपको http://www.applecom/pages से http://search.dnsassist.verizon.net/assist.php?url=www.applecom
से रीडायरेक्ट किया गया था 210
आप इस बारे में सोचना चाहते हैं कि किस प्रकार के रीडायरेक्ट स्वीकार्य हैं (उदाहरण के लिए, यदि आप "www.adobephotoshop.com" पर जाते हैं और यह आपको "www.adobe.com" पर रीडायरेक्ट करता है) और किस प्रकार नहीं हैं (उदाहरण के लिए, अगर मैं "www.applecom" पर जाता हूं और यह मुझे "search.dnsassist.verizon.net" पर रीडायरेक्ट करता है। मैं काफी संकीर्ण समस्या के बारे में चिंतित हो सकता हूं (जो मेरे आईएसपी के कारण मुझे प्रभावित करता है), लेकिन यह सोचने के लिए कुछ है।
वैसे, लोड वास्तव में असफल रहा है, या आपको 404 त्रुटि मिल रही है (जो, वेब दृश्य के परिप्रेक्ष्य से, कोई त्रुटि नहीं है)। – Rob
@Rob धन्यवाद। 404 त्रुटि, लेकिन मुझे नहीं पता कि – Jack