Android-приложение Phonegap ajax запрашивает HTTPS с ошибкой со статусом 0

HTTPS-запросы Ajax из моего приложения PhoneGap/Cordova на Android по необъяснимым причинам завершаются сбоем со статусом =0. Он появляется только при подписании приложения с помощью ключа разблокировки (т. Е. При экспорте из ADT), но не отображается при подписи с помощью ключа отладки (работает непосредственно в эмуляторе или на телефоне).

request = new XMLHttpRequest()
request.open "GET", "https://some.domain/", true
request.onreadystatechange = ->
  console.log "** state = " + request.readyState
  if request.readyState is 4
      console.log "** status = " + request.status

request.send()

всегда выводит

** state = 4
** status = 0

Неважно, если я устанавливаю приложение из Play Store или с adb полезность. Я предполагаю, что это может быть связано с сертификатом, так как не все домены HTTPS терпят неудачу таким образом.

5 ответов

Решение

Это происходит, когда запрошенный URL-адрес отвечает ошибочным или самозаверяющим сертификатом. Во время тестирования или распространения приложения среди друзей, настройка <application android:debuggable="true"...> в AndroidManifest.xml достаточно - он автоматически обходит ошибки сертификата.

Но Google Play Store не примет APK с android:debuggable="true", Прежде всего, сертификаты, конечно, должны быть исправлены. Но пока это происходит, вот обходной путь для PhoneGap/Cordova 3:

  1. В вашем пакете приложения создайте подкласс для CordovaWebViewClient:

    public class SSLAcceptingCordovaWebViewClient extends CordovaWebViewClient {
        public SSLAcceptingCordovaWebViewClient(CordovaInterface cordova, CordovaWebView view) {
            super(cordova, view);
        }
    
        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
            handler.proceed();
        }
    }
    
  2. То же самое для IceCreamCordovaWebViewClient:

    public class SSLAcceptingIceCreamCordovaWebViewClient extends IceCreamCordovaWebViewClient {
        public SSLAcceptingIceCreamCordovaWebViewClient(CordovaInterface cordova, CordovaWebView view) {
            super(cordova, view);
        }
    
        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
            handler.proceed();
        }
    }
    
  3. в <Your App Name>.java добавить переопределение для makeWebViewClient:

    @Override
    protected CordovaWebViewClient makeWebViewClient(CordovaWebView webView) {
        if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB) {
            return new SSLAcceptingCordovaWebViewClient(this, webView);
        } else {
            return new SSLAcceptingIceCreamCordovaWebViewClient(this, webView);
        }
    }
    

И вуаля! Ошибки SSL будут игнорироваться. Однако никогда не используйте ошибочные сертификаты. Попробуйте сначала исправить их и используйте этот грязный обходной путь только тогда, когда у вас закончатся другие решения.

У меня была та же проблема, но мое решение было немного другим.

  1. Только в сборке приложения Android для моего приложения Cordova вызовы AJAX на мой сервер через HTTPS блокировались. Не в iOS, не в настольных браузерах. Самое странное, что в реальном браузере Android вызовы HTTPS AJAX не будут работать без проблем.

  2. Я подтвердил, что могу делать HTTPS AJAX-вызовы на хорошо известные и надежные URL-адреса, такие как https://google.com/ а также регулярные HTTP-вызовы на любой URL-адрес, который мне хотелось попробовать.

  3. Это заставило меня поверить, что мой SSL-сертификат либо НЕ был установлен на 100% правильно, либо дешевым (~ 10 долларов США) сертификатом от PositveSSL не был универсально доверенным, ИЛИ ни тем, ни другим.

  4. Мой сертификат был установлен на AWS Load Balancer, поэтому я огляделся по поводу того, как, возможно, я все испортил, а также по поводу того, что PositiveSSL был не лучшим сертификатом для использования с точки зрения надежности. К счастью, я нашел статью, посвященную установке сертификатов AWS ELB, и они использовали сертификат PositiveSSL! Внутри был этот маленький драгоценный камень:

"... Не обманывайтесь диалогом AWS, цепочка сертификатов не является обязательной, когда ваш ELB общается напрямую с браузером..."

http://www.nczonline.net/blog/2012/08/15/setting-up-ssl-on-an-amazon-elastic-load-balancer/

Барабанная дробь....

Я переустановил сертификат с "дополнительной" информацией о цепочке сертификатов и вуаля! HTTPS AJAX-звонки на мой сервер начали работать.

Таким образом, кажется, что веб-представление Android является более консервативным, чем браузер Android с точки зрения доверия. Это не совсем интуитивно понятно, поскольку предполагается, что они в основном одни и те же технологии.

Другой вариант, который также работает, - это перекомпилировать базовый файл cordova.jar, чтобы тест был полностью удален, поэтому нет причин беспокоиться о том, что ваш сертификат действителен или нет. Я столкнулся с проблемой из-за того, что Android не распознает сертификат GoDaddy, который был на сервере. Сертификат показывает действительный на iOS, но даже при просмотре с Android жаловался на сертификат. Это из ветки 2.9.x, так как это то, с чем я работал.

cordova-android / framework / src / org / apache / cordova / CordovaWebViewClient.java

@TargetApi(8)
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {

    final String packageName = this.cordova.getActivity().getPackageName();
    final PackageManager pm = this.cordova.getActivity().getPackageManager();

    ApplicationInfo appInfo;
    try {
        appInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
        handler.proceed();
        return;

        /* REMOVED TO BY PASS INVALID CERT CHAIN ****
        if ((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
            // debug = true
            handler.proceed();
            return;
        } else {
            // debug = false
            super.onReceivedSslError(view, handler, error);
        }*/
    } catch (NameNotFoundException e) {
        // When it doubt, lock it out!
        super.onReceivedSslError(view, handler, error);
    }
}

ПРИМЕЧАНИЕ. Я понимаю, что это небезопасно, но когда все остальное не помогло, это решило проблему, которая продолжалась в течение более 2 месяцев, включая переустановку сертификата в соответствии с руководством по установке цепочки сертификатов, и рядом с ним находится сайт, который является нашей собственной, а не третьей стороной, поэтому независимо от того, действителен он или нет, он подключается только к этому серверу.

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

Вы можете легко проверить это онлайн, если ваша цепочка сертификатов правильная, вы найдете много на Google, например, https://www.sslshopper.com/ssl-checker.html

В Apache2 это часть директивы VirtualHost 443, в вашей директиве есть три правила, это выглядит так:

SSLCertificateFile    /etc/apache2/ssl/mycert.crt

SSLCertificateKeyFile /etc/apache2/ssl/mykey.key

SSLCertificateChainFile  /etc/apache2/ssl/certification_auth_intermediate.crt

Вы не можете использовать готовые (phonegap) apks с самозаверяющими сертификатами. Посмотрите на этот ответ, чтобы получить дополнительную информацию.

Л.Г.

fastrde

Другие вопросы по тегам