UIWebView не загружает страницу HTTPS: Error Domain = NSURLErrorDomain Code = -999 "Операция не может быть завершена (ошибка NSURLErrorDomain -999.)"

Примечание. Этот вопрос по-прежнему не отвечает!

Я использую UIWebView для загрузки следующих URL-адресов:

https://buchung.salonmeister.de/ort/301655/menue/#offerId=907601&venueId=301655

https://buchung.salonmeister.de/place/#offer-details-page?id=907599&venueId=301655

http://feratel.lueneburger-heide.de/lhg/de/accommodation/detail/LUH/8634e147-e13d-40f5-8954-2ac40cfea2a7/romantik_hotel_bergström?customHeader=true

http://feratel.lueneburger-heide.de/lhg/de/accommodation/detail/LUH/8af6d1fd-af6d-4765-8025-9eb8fa05ea42/hotel%20undeloher%20hof?customHeader=true

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

При попытке загрузки я получаю следующую ошибку из func webView(webView: UIWebView, didFailLoadWithError error: NSError):

Ошибка домена = NSURLErrorDomain Code = -999 "Операция не может быть выполнена. (NSURLErrorDomain error -999.)" UserInfo = 0x7ff7d0fd6f20 {NSErrorFailingURLStringKey = https://buchung.salonmeister.de/ort/301655/menue/#offerId=907601&venueId=301655, NSErrorFailingURLKey = https://buchung.salonmeister.de/ort/301655/menue/#offerId=907601&venueId=301655}

Я тестировал код ниже на iOS7 и iOS8. Mobile Safari загружает эту страницу без каких-либо проблем, но в моем UIWebView я ничего не вижу.

Вот код, который я использую:

class ViewController: UIViewController, UIWebViewDelegate, NSURLConnectionDataDelegate {
  @IBOutlet weak var webView: UIWebView!
  var request: NSURLRequest!
  var urlString: String!
  private var isDone: Bool = false
  private var failedRequest: NSURLRequest!

  override func viewDidLoad() {
    super.viewDidLoad()

    urlString = "https://buchung.salonmeister.de/ort/301655/menue/#offerId=907601&venueId=301655"
    request = NSURLRequest(URL: NSURL(string: urlString)!)
    webView.delegate = self
  }

  override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    self.webView.loadRequest(self.request)
  }

  // MARK: UIWebViewDelegate

  func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
    println("shouldStartLoadWithRequest()")

    if !isDone {
      isDone = false

      println("shouldStartLoadWithRequest() 111")
      failedRequest = request
      webView.stopLoading()
      var connection = NSURLConnection(request: request, delegate: self, startImmediately: true)
      connection!.start()
      //      NSURLConnection(request: request, delegate: self)
      return false
    }
    println("shouldStartLoadWithRequest() -----------------------")
    return true
  }

  func webViewDidStartLoad(webView: UIWebView) {
    println("webViewDidStartLoad()")
  }

  func webViewDidFinishLoad(aWebView: UIWebView) {
    println("webViewDidFinishLoad()")
  }

  func webView(webView: UIWebView, didFailLoadWithError error: NSError) {
    println("webView(): didFailLoadWithError(): \(error)")
  }

  // MARK: NSURLConnectionDataDelegate

  func connection(connection: NSURLConnection, willSendRequestForAuthenticationChallenge challenge: NSURLAuthenticationChallenge) {
    println("connection willSendRequestForAuthenticationChallenge")

    if challenge.previousFailureCount == 0 {
      self.isDone = true
      println("x1")
      let credential: NSURLCredential = NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!)
      challenge.sender.useCredential(credential, forAuthenticationChallenge: challenge)

    }
    else {
      println("x2")
      challenge.sender.cancelAuthenticationChallenge(challenge)
    }
  }

  func connection(connection: NSURLConnection, didReceiveResponse response: NSURLResponse) {
    println("connection didReceiveResponse")
    self.isDone = true

    connection.cancel()
    self.webView.loadRequest(self.failedRequest)
  }

  func connection(connection: NSURLConnection, canAuthenticateAgainstProtectionSpace protectionSpace: NSURLProtectionSpace) -> Bool {
    println("connection canAuthenticateAgainstProtectionSpace")
    return protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust
  }
}

Я создал образец проекта с приведенным выше кодом здесь: https://github.com/confile/UIWebView-https-url

Как я могу правильно загрузить свой UIWebView URL-адрес?

Ответы

Ответ 1

Я запустил ваш код. Он работал нормально примерно в 50% случаев и показал ошибку -999 в другое время.

Этот код ошибки NSURLErrorCancelled, согласно Кодам ошибок системы загрузки URL-адресов в Справочнике констант Apple Foundation. Так что что-то отменяет загрузку страницы.

Я напечатал полученное содержимое страницы, используя это:

println(aWebView.stringByEvaluatingJavaScriptFromString("document.body.innerHTML"));

Я вижу, что Javascript на странице содержит следующее:

if (mobilePath) {
   document.body.style.display = 'none';
   document.location = mobilePath;  
}

Я предполагаю, что этот Javascript начинает работать, как только загружается контент. Это приводит к условию гонки, когда иногда страница сразу перенаправляется на другой document.location, поэтому загрузка первой страницы отменяется до полной загрузки.

Вы должны изменить сервер, чтобы он не отправил этот Javascript.

В качестве альтернативы, если вы просто хотите загрузить веб-сайт, как обычный веб-сайт, вы можете позволить UIWebView обрабатывать перенаправления для вас. В случае с этим сайтом я получил его работоспособным образом, установив User-agent, чтобы притвориться мобильным Safari. Я также удалил shouldStartLoadWithRequest, потому что это только мешало вещам.

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    var request = NSMutableURLRequest(URL: NSURL(string: urlString)!)
    var userAgent = ["UserAgent": "mozilla/5.0 (iphone; cpu iphone os 7_0_2 like mac os x) applewebkit/537.51.1 (khtml, like gecko) version/7.0 mobile/11a501 safari/9537.53"]
    NSUserDefaults.standardUserDefaults().registerDefaults(userAgent as [NSObject : AnyObject])

    self.webView.loadRequest(request)
  }

Если у меня нет кода, чтобы притворяться мобильным Safari, тогда содержимое страницы загружается, но оно не подходит. Он просто останавливается у спиннера. Я полагаю, что веб-сайт отправляет разные Javascript в зависимости от того, с каким движком рендеринга он думает, с кем разговаривает. Если вы не укажете какого-либо User-agent, тогда вы будете во власти того, что их веб-дизайнер сделал с точки зрения определения поведения по умолчанию.