web-dev-qa-db-ja.com

UIWebViewでHTTPエラーコードを検出して処理する方法は?

HTTPエラー404などを受信したときにユーザーに通知したい。どうすればそれを検出できますか?私はすでに実装しようとしました

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error

しかし、404エラーを受け取ったときに呼び出されません。

19
EEE

ここでURLRequestをキャプチャできます。

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType

リクエストをデリゲートに渡して、いいえを返します。次に、NSURLConnectionから受信した応答呼び出しで接続をキャンセルし、すべてが正常である場合(応答を確認)、Webビューにurlrequestをもう一度ロードします。 urlrequestを再度ロードするときは、上記の呼び出しで必ずYESを返します。

あまりエレガントではありませんが、うまくいくかもしれません。

7
Felix Lamouroux

Radu Simionescuの応答に触発された私の実装:

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    NSCachedURLResponse *urlResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:webView.request];
    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*) urlResponse.response;
    NSInteger statusCode = httpResponse.statusCode;
    if (statusCode > 399) {
        NSError *error = [NSError errorWithDomain:@"HTTP Error" code:httpResponse.statusCode userInfo:@{@"response":httpResponse}];
        // Forward the error to webView:didFailLoadWithError: or other
    }
    else {
        // No HTTP error
    }
}

HTTPクライアントエラー(4xx)とHTTPサーバーエラー(5xx)を管理します。

応答がキャッシュされていない場合、cachedResponseForRequestnilを返すことに注意してください。その場合、statusCodeは0に割り当てられ、応答はエラーなしと見なされます。

18
Axel Guilmin

UIWebViewは、ロードするリクエストのHTTPステータスコードを取得するための機能を提供していません。回避策の1つは、UIWebViewDelegateメソッドを使用してUIWebViewの要求読み込みプロセスをインターセプトし、NSURLConnectionを使用して、サーバーがその要求にどのように応答するかを検出することです(上記のとおり)。その後、状況に適した適切なアクションを実行できます。

また、応答を受信した後、要求のロードを続行する必要はありません。 HTTPステータスコードを学習した後、void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)responseメソッドで接続をキャンセルできます。このようにして、接続が不要な応答データをロードするのを防ぎます。次に、リクエストをUIWebViewに再度ロードするか、HTTPステータスコードなどに応じて適切なエラーメッセージをユーザーに表示できます。

---(そしてこれがgithubのデモプロジェクトです

8
Ahmet Ardal

-didFailLoadWithErrorの目的を誤って解釈しています。技術的には、リクエストは成功しました。サーバーにアクセスし、要求しているファイルが存在しないことを検出できました(つまり、404)。たとえば、サーバーが存在しない場合、-didFailLoadWithErrorメソッドが呼び出されます。サーバーが存在します。ファイルはそうではありません。 Webビューは、コンテンツのエラーを解釈しません。 UIWebViewDelegate Appleドキュメントからの-didFailLoadWithErrorの目的は次のとおりです。

Webビューがコンテンツのロードに失敗した場合に送信されます。

HTTP 404 に関するウィキペディアの記事から:

404またはNotFoundエラーメッセージは、クライアントがサーバーと通信できたが、サーバーが要求されたものを見つけることができなかったことを示すHTTP標準応答コードです。 404エラーは、宛先サーバーへの接続がまったく確立できなかった「サーバーが見つかりません」または同様のエラーと混同しないでください。

おそらく、WebビューではなくNSURLConnection/NSURLRequestの組み合わせで取得できる404の応答テキストを解析する必要があります。

宜しくお願いします、

7
Matt Long

NSURLConnectionはあなたが探しているクラスです、私はこれがUIWebViewで直接行うことができるとは思いません。

同期方式を使用できます

+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error

または非同期のもの。 1 NSDataに取得するデータのすべてのビットを追加する必要があるため、これらのセットアップは困難ですが、最終的な結果は同じです。


同期方式と非同期方式のどちらを使用するかに関係なく:

NSError *オブジェクトを取得した場合は、COMMSエラーが発生しています。他の応答に記載されているように、これはHTTPステータスコードではなく、通信の問題です。

接続が成功すると、NSURLResponseとNSDataを取得します。重要なのは、HTTPリクエストのNSURLResponseが実際にはNSHTTPURLResponseサブクラスであるということです。

次に、応答をチェックしてエラーコードを確認する必要があります。これを試してください(ここで_responseInfoはNSURLResponseオブジェクトです):

  NSInteger httpStatusCode = (NSHTTPURLResponse*)_responseInfo.statusCode;

responseInfoは常にHTTPリクエストのNSHTTPURLResponseである必要があります...ただし、万が一の場合に備えて、そこにアサートを設定することをお勧めします。

StatusCodeが成功(つまり200)の場合、NSDataオブジェクトには応答のデータ(それが何であれ)が含まれている必要があります。ステータスコードがエラーを示している場合、NSDataにはサーバーからのエラーのテキストによる説明が含まれている可能性があります。

注意。エラーメッセージのNSDataオブジェクトを解析するためにタイリングすることは本当にお勧めしません。それがHTTP'statusCode 'の目的です!

7
William Denniss

私はiOSとSwift開発に不慣れで、UIではなくWKWebViewを使用してこれを達成する方法を見つける必要がありました。幸運にも遭遇しました このサイト は、私のニーズにぴったりの次の答えをくれました。私と同じ答えを探している通行人に役立つかもしれません。

この関数の使用(WKNavigationDelegateから):

func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void)

次のように、HTTP応答に基づいてカスタム応答を作成できます。

func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {

    // get the statuscode
    guard let statusCode = (navigationResponse.response as? HTTPURLResponse)?.statusCode
    else {
        decisionHandler(.allow)
        return
    }

    // respond or pass-through however you like
    switch statusCode {
    case 400..<500:
        webView.loadHTMLString("<html><body><h1>You shall not pass!</h1></body></html>", baseURL: nil)
    case 500..<600:
        webView.loadHTMLString("<html><body><h1>Sorry, our fault.</h1></body></html>", baseURL: nil)
    default:
        print("all might be well")
    }

    decisionHandler(.allow)
}
2
AlienFromCA

WebViewDidFinishLoadの場合:

if ([[(NSHTTPURLResponse*)[[NSURLCache sharedURLCache] cachedResponseForRequest:webView.request] valueForHTTPHeaderField:@"Status"] intValue] == 404){
}

一部の応答がキャッシュされない場合でも、このソリューションを他のより複雑なソリューションよりも検討することができます。間違ったURLは通常、デフォルト設定のシステムによってキャッシュされることに注意してください。

2
Radu Simionescu

これが私のSwift 3バージョンの@AxelGuilmin応答です:

func webViewDidFinishLoad(_ webView: UIWebView) {

        guard let request = webView.request else { return }

        let cachedUrlResponse = URLCache.shared.cachedResponse(for: request)
        let httpUrlResponse = cachedUrlResponse?.response as? HTTPURLResponse
        if let statusCode = httpUrlResponse?.statusCode {
            if statusCode == 404 {
                // Handling 404 response
            }
        }
    }
1
Mindhavok