Iphone 如何从UIWebView获取最后一个HTTP状态代码?
我想检测给UIWebView的页面加载请求何时返回5xx或4xx范围内的状态代码 我已经为web视图设置了委托,并提供了一个-webView:didFailLoadWithError:error方法,但是尽管它在超时时会被很好地调用,但在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
有什么建议吗?嗯。。。我不是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加载系统不会将它们视为错误