【问题标题】:How to detect and handle HTTP error codes in UIWebView?如何检测和处理 UIWebView 中的 HTTP 错误代码?
【发布时间】:2011-01-15 05:41:24
【问题描述】:

我想在收到 HTTP 错误 404 等时通知用户。我怎样才能检测到呢? 我已经尝试实现了

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

但是当我收到 404 错误时它不会被调用。

【问题讨论】:

    标签: ios objective-c iphone uiwebview nserror


    【解决方案1】:

    UIWebView 不提供任何功能来获取其加载的请求的 HTTP 状态代码。一种解决方法是使用 UIWebViewDelegate 方法拦截 UIWebView 的请求加载过程,并使用 NSURLConnection 检测服务器如何响应该请求(如上所述)。然后,您可以采取适合情况的适当措施。

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

    and here is the demo project on github

    【讨论】:

      【解决方案2】:

      我是 iOS 和 Swift 开发的新手,也需要找到一种方法来完成此任务,使用 WKWebView(而不是 UI)。我很幸运遇到了this site,它给了我以下答案,非常适合我的需求。它可能会帮助正在寻找与我相同的答案的路人。

      使用这个函数(来自 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)
      }
      

      【讨论】:

        【解决方案3】:

        这是我对@AxelGuilmin 的 swift 3 版本的回复:

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

        【讨论】:

          【解决方案4】:

          我的实施灵感来自 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)。

          请注意,如果响应未缓存,cachedResponseForRequest 返回 nil,在这种情况下,statusCode 被分配为 0,并且响应被认为是无错误的。

          【讨论】:

          • 谢谢,我认为您的回答是最正确的方法。
          • 我一直在拔头发,直到我在真实设备上进行了测试,模拟器总是为我返回 404。直到我在 iPad 上试用它才真正起作用!
          【解决方案5】:

          我的解决方案使用了以下代码

          -(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error{
          NSLog(@"error  :%@",error);
          
          NSString *strError = [NSString stringWithFormat:@"%@",error];
          
          if ([strError rangeOfString:@"Code=-1005"].location == NSNotFound) {
              NSLog(@"string does not contain Code=-1005");
          } else 
              NSLog(@"string contains Code=-1005”);
          

          }

          【讨论】:

            【解决方案6】:

            在 webViewDidFinishLoad 中:

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

            您可以考虑使用此解决方案而不是其他更复杂的解决方案,即使某些响应可能不会被缓存。请注意,错误的 url 通常会被具有默认配置的系统缓存。

            【讨论】:

              【解决方案7】:

              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' 的用途!

              【讨论】:

                【解决方案8】:

                您误解了 -didFailLoadWithError 的用途。从技术上讲,请求成功了。它能够访问服务器并发现您请求的文件不存在(即 404)。例如,如果服务器不存在,将调用 -didFailLoadWithError 方法。您的服务器存在。文件没有。 Web 视图不会解释内容中的错误。 UIWebViewDelegate Apple Docs 中的 -didFailLoadWithError 的目的是:

                在网页视图加载失败时发送 内容。

                来自HTTP 404 上的维基百科文章:

                404 或未找到错误消息是 HTTP 标准响应代码 表明客户能够 与服务器通信,但 服务器找不到是什么 请求。不应出现 404 错误 与“找不到服务器”混淆或 类似的错误,其中一个连接 无法到目标服务器 完全做到了。

                您很可能必须解析 404 的响应文本,您可以使用 NSURLConnection/NSURLRequest 组合而不是 Web 视图获得。

                最好的问候,

                【讨论】:

                • 感谢您的回复。我只是误解了 didFailLoadError 方法。
                • 解析错误代码的响应文本是个坏主意,响应文本可以是任何东西!有关获取 HTTP 状态码的真正方法,请参阅我的答案。
                【解决方案9】:

                您可以在此处捕获 URLRequest:

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

                并将请求交给委托人并返回否。然后在收到来自NSURLConnection 的响应调用中取消连接,如果一切正常(检查响应),再次在 web 视图中加载 urlrequest。再次加载 urlrequest 时,请确保在上述调用中返回 YES。

                不是很优雅,但它可能会起作用。

                【讨论】:

                • 感谢您的回复。如何在 html 字符串中搜索字符串?我被困在了那里。
                • 如果您捕获了请求,您可以启动自己的NSUrlconnection 并收集接收到的连接数据,然后您可以在connectionDidFinishLoading 中访问html。
                • 其实我已经访问了html,问题是在objective-c中搜索html中的字符串,但是我已经用C解决了。谢谢。
                • 这意味着每个请求都要两次......这是错误的
                • 是的,您可以收到状态码,但您提出了两次请求..?这实际上并不好
                猜你喜欢
                • 2011-12-09
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-06-10
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多