Как получить последний код состояния HTTP из UIWebView? - PullRequest
14 голосов
/ 30 июня 2009

Я хотел бы определить, когда запрос загрузки страницы, переданный UIWebView, возвращает код состояния в диапазоне 5xx или 4xx.

Я настроил делегата для веб-представления и предоставил метод -webView: didFailLoadWithError: error, но хотя он вызывается нормально для тайм-аутов, он не вызывается для ошибок кода состояния HTTP.

Есть предложения?

Ответы [ 9 ]

10 голосов
/ 30 июня 2009

Хммм ... Я не разработчик для iPhone, но ....

Не могли бы вы попытаться создать NSURLRequest с URL-адресом, который вы хотите загрузить? Затем вы можете установить соединение, используя NSURLConnection.

NSURLConnection имеет метод делегата

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response

, который даст ответ от сервера. Обратите внимание, что если вы устанавливаете соединение через HTTP, ответ на самом деле будет иметь класс NSHTTPURLResponse. NSHTTPURLResponse можно использовать для получения статуса, используя следующий метод экземпляра

- (NSInteger)statusCode

NSURLConnection имеет другой метод делегата

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data

, который можно использовать для получения данных из URL-соединения. Затем вы можете вручную загрузить данные в ваш UIWebView, используя:

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

Это похоже на тонну работы, но это можно сделать. Надеюсь, кто-то еще придумает более легкий путь, хотя я его не вижу.

4 голосов
/ 21 февраля 2012

Я долго боролся с этим, пытаясь найти хороший ответ. Требования, над которыми я работал, заключались в том, что я должен был иметь возможность определять статус загрузки ПЕРВОЙ страницы и любую нагрузку после этого, я бы предположил, что пользователь щелкает ссылки, которые не должны быть нарушены (не гарантировано, я знаю, , но намного лучше, чем альтернативы).

В итоге я сам сделал первоначальный вызов через 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

перехватывать все запросы и делать их самостоятельно. Вам понадобится какой-то метод управления запросами, потому что, когда вы вызываете loadData для UIWebView, он вызывает обратный вызов shouldStartLoadWithRequest, и вы хотите убедиться, что вы не выполняете бесконечный цикл повторения одного и того же запроса и более.

3 голосов
/ 11 ноября 2016

Я очень тяжело боролся с этой темой, когда все включено Swift 3.0 сейчас. Я даже создал собственный URLProtocol и попытался перехватить все веб-запросы, чтобы в конце концов понять, что это не нужно. Причина путаницы для меня в том, что они переместили функцию didReceiveResponse:

optional public func connection(_ connection: NSURLConnection, didReceive response: URLResponse)

до NSURLConnectionDataDelegate , который наследуется от NSURLConnectionDelegate.

В любом случае, вот версия 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)
}
2 голосов
/ 01 апреля 2014

Вот обходной путь для получения кода ответа 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;
}
2 голосов
/ 19 августа 2011

В настоящее время UIWebView не предоставляет никаких функций для получения кодов состояния HTTP для запросов, которые он загружает. Одним из обходных путей является перехват процесса загрузки запроса UIWebView с использованием методов UIWebViewDelegate и использование NSURLConnection для определения того, как сервер отвечает на этот запрос. Тогда вы можете предпринять соответствующее действие, подходящее для ситуации. Эта статья подробно описывает обходной путь для демонстрационного проекта.

И вам не нужно продолжать загружать запрос после получения ответа. Вы можете просто отменить соединение в - (void) соединение: (NSURLConnection *) connection didReceiveResponse: (NSURLResponse *) ответ метод после изучения кода состояния HTTP. Таким образом вы предотвращаете загрузку соединения ненужных данных ответа. Затем вы можете снова загрузить запрос в UIWebView или показать пользователю соответствующее сообщение об ошибке в зависимости от кода состояния HTTP и т. Д.

Вот статья

и вот демонстрационный проект на github

1 голос
/ 11 июля 2012

Как я только что опубликовал в другой теме , также возможно перехватить любую NSURLRequest на уровне NSURLProtocol и создать там NSURLResponse вместо вашего делегата UIWebView / контроллер. Причина, по которой это предпочтительнее, на мой взгляд, заключается в том, что он поддерживает стек навигации назад / вперед UIWebView. Схема подхода может быть найдена в этом превосходном сообщении в блоге Робом Напиром:

http://robnapier.net/blog/offline-uiwebview-nsurlprotocol-588

и на GitHub есть код:

https://github.com/rnapier/RNCachingURLProtocol

0 голосов
/ 30 марта 2013

Вот хороший пример, где они используют комбинацию создания NSURLConnection для первой загрузки и UIWebView для следующих страниц:

http://www.ardalahmet.com/2011/08/18/how-to-detect-and-handle-http-status-codes-in-uiwebviews/

По сути, это основной трюк, использующий возвращаемое значение YES / NO для shouldStartLoadRequest:

- (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;
}

Это должно помочь вам без использования синхронных запросов, особенно в сочетании с ответом Джеффа.

0 голосов
/ 30 июня 2009

К сожалению, в настоящее время похоже, что наилучшим доступным вариантом является использование -stringByEvaluatingJavaScriptFromString: для запуска какого-то небольшого сценария, который запрашивает у документа его код состояния.

0 голосов
/ 30 июня 2009

Как насчет реализации webViewDidFinishLoad: на вашем UIWebViewDelegate и использования свойства request UIWebView для доступа к интересующим вас заголовкам? Примерно так (не проверено):

- (void)webViewDidFinishLoad:(UIWebView *)webView {
  NSString* theStatus = [[webView request] valueForHTTPHeaderField:@"Status"];
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...