Iphone 如何从UIWebView获取最后一个HTTP状态代码?

Iphone 如何从UIWebView获取最后一个HTTP状态代码?,iphone,cocoa,cocoa-touch,Iphone,Cocoa,Cocoa Touch,我想检测给UIWebView的页面加载请求何时返回5xx或4xx范围内的状态代码 我已经为web视图设置了委托,并提供了一个-webView:didFailLoadWithError:error方法,但是尽管它在超时时会被很好地调用,但在HTTP状态代码错误时不会被调用 有什么建议吗?嗯。。。我不是iPhone开发者,但是 能否尝试使用要加载的URL创建NSURLRequest?然后可以使用NSURLConnection建立连接 NSURLConnection有一个委托方法 - (void)co

我想检测给UIWebView的页面加载请求何时返回5xx或4xx范围内的状态代码

我已经为web视图设置了委托,并提供了一个-webView:didFailLoadWithError:error方法,但是尽管它在超时时会被很好地调用,但在HTTP状态代码错误时不会被调用


有什么建议吗?

嗯。。。我不是iPhone开发者,但是

能否尝试使用要加载的URL创建NSURLRequest?然后可以使用NSURLConnection建立连接

NSURLConnection有一个委托方法

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
这将给出服务器的响应。请注意,如果您是通过HTTP进行连接,那么响应实际上将属于NSHTTPURLResponse类。NSHTTPURLResponse可用于使用以下实例方法获取状态

- (NSInteger)statusCode
NSURLConnection有另一个委托方法

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
可用于从URL连接获取数据的。然后,您可以使用以下方法手动将数据加载到UIWebView中:

- (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL

这似乎是一大堆工作,但它是可以做到的。希望其他人能想出更简单的方法,尽管我看不到。

在您的
UIWebViewDelegate
上实现
webViewDidFinishLoad:
,并使用UIWebView的
request
属性访问您感兴趣的标题怎么样?类似这样(未经测试):


遗憾的是,目前最好的选择似乎是使用-stringByEvaluatingJavaScriptFromString:运行某种小型脚本,查询文档的状态代码。

目前,UIWebView不提供任何功能来获取加载请求的HTTP状态代码。一种解决方法是使用UIWebViewDelegate方法拦截UIWebView的请求加载过程,并使用NSURLConnection检测服务器如何响应该请求。然后你可以采取适合情况的适当行动。详细说明演示项目的解决方法

在收到响应后,您不需要继续加载请求。学习HTTP状态代码后,您只需在-(void)connection:(NSURLConnection*)connection didReceiverResponse:(nsurResponse*)response方法中取消连接即可。这样可以防止连接加载任何不必要的响应数据。然后,您可以在UIWebView中再次加载请求,或者根据HTTP状态代码等向用户显示适当的错误消息


为了找到一个好的答案,我费了好长一段时间才明白这一点。我当时的工作要求是,我需要能够确定第一个页面加载的状态,以及之后的任何加载状态,我会假设用户正在单击不应该被破坏的链接(我知道,这不是保证,但比其他选择要好得多)

最后我自己通过一个NSURLConnection(同步)进行了初始调用,然后将数据传递到UIWebView

NSURL *googleURL = [NSURL URLWithString:@"http://www.google.com"];
NSURLRequest *googleRequest = [NSURLRequest requestWithURL:googleURL];
NSHTTPURLResponse *response;
NSError *error;
NSData *responseData = [NSURLConnection sendSynchronousRequest:googleRequest
                                             returningResponse:&response 
                                                         error:&error];

if ([response statusCode] >= 400 || error)
{
    // handle error condition
} else {
    [webView_ loadData:responseData MIMEType:[response MIMEType] 
                            textEncodingName:[response textEncodingName] 
                                     baseURL:[response URL]];
    [self setView:webView_];
}
如果您希望获得每个请求的信息,您可以简单地使用该方法

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
截取所有请求并自行发出。您必须使用某种请求管理技术,因为当您在UIWebView上调用loadData时,它将调用shouldStartLoadWithRequest回调,并且您希望确保不会重复执行无限循环来发出相同的请求。

正如我刚刚发布的,还可以在
nsurl协议
级别截取任何
nsurl请求
,并在那里而不是在UIWebView代理/控制器中创建
nsurl响应
。我认为这更可取的原因是它维护UIWebView的向后/向前导航堆栈。罗布·纳皮尔(Rob Napier)的这篇优秀博文中提供了该方法的概要:

GitHub上有代码:


这是一个很好的例子,他们在第一次加载时创建NSURLConnection,在接下来的页面中创建UIWebView:

基本上,这是主要技巧,使用shouldStartLoadRequest的YES/NO返回值:

- (BOOL) webView:(UIWebView *)webView 
     shouldStartLoadWithRequest:(NSURLRequest *)request 
                 navigationType:(UIWebViewNavigationType)navigationType
{
    if (_sessionChecked) {
        // session already checked.
        return YES;
    }

    // will check session.

    NSURLConnection *conn = [NSURLConnection connectionWithRequest:request delegate:self];
    if (conn == nil) {
        NSLog(@"cannot create connection");
    }
    return NO;
}

这应该可以让您不用使用同步请求,尤其是与Jeff的答案结合使用。

这里有一个获取HTTP响应代码的解决方案,但只需向每个URL发送一个请求即可:-

BOOL isLoad;
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
    NSLog(@"Requesting: %@ - %d - %@", request.URL.absoluteString, navigationType, request.URL.host);
    if (navigationType != UIWebViewNavigationTypeOther) {
        //Store last selected URL
        self.loadedURL = request.URL.absoluteString;
    }
    if (!isLoad && [request.URL.absoluteString isEqualToString:loadedURL]) {
        [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
            if (connectionError || ([response respondsToSelector:@selector(statusCode)] && [((NSHTTPURLResponse *)response) statusCode] != 200 && [((NSHTTPURLResponse *)response) statusCode] != 302)) {
                //Show error message
                [self showErrorMessage];
            }else {
                isLoad = YES;
                [_wbView loadData:data MIMEType:[response MIMEType]
                 textEncodingName:[response textEncodingName]
                          baseURL:[response URL]];
            }
        }];
        return NO;
    }
    isLoad = NO;
    return YES;
}

当我现在使用Swift 3.0时,我在这个话题上非常努力。我甚至创建了一个自定义的URLProtocol,并试图拦截所有的web请求,只是为了最终意识到这是不必要的。我感到困惑的原因是他们移动了didReceiveResponse函数:

optional public func connection(_ connection: NSURLConnection, didReceive response: URLResponse)
到从NSURLConnectionDelegate继承的NSURLConnectionDataDelegate

无论如何,以下是Swift 3.0版本:

// You first need to have NSURLConnectionDataDelegate on your UIWebView

// MARK: - get HTTP status code

// setup urlconnectiondelegate
// so that the didReceiveResponse is called
func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
    let conn: NSURLConnection? = NSURLConnection(request: request, delegate: self)
    if conn == nil {
        print("cannot create connection")
    }
    return true;
}

// intercept the actual http status code
func connection(_ connection: NSURLConnection, didReceive response: URLResponse) {
    let httpResponse: HTTPURLResponse = response as! HTTPURLResponse;
    print(httpResponse.statusCode)
}

错。为什么请求对象包含服务器返回的状态?是的,这是错误的。请求和响应是两件不同的事情。这当然是一种可能的解决方案。这意味着同样的工作要做两次,虽然很遗憾,但我不知道为什么会被否决。当然,这不容易,但会奏效的。事实上,这(可能)是唯一的“官方”方式。仔细想想,这其实并不难。关于如何设置NSURLConnection,然后使用委托方法获取数据,在线上有大量示例代码。请注意,
direceivedata:
不会向您的学员提供数据;它为您的学员提供了一些数据。您将需要收集整个数据,直到连接完成,或者找到某种方法将这些增量数据块提供给UIWebView。可以直接连接到UIWebView加载,请参见下面的我的响应……对于HTTP状态代码错误,不会调用它,因为URL加载系统不会将它们视为错误