Phonegap Android应用通过HTTPS发送ajax请求失败,状态码为0。

15

我的PhoneGap/Cordova应用在Android上通过Ajax HTTPS请求不可理解地失败,状态码为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个回答

14

我遇到了同样的问题,但我的解决方案略有不同。

  1. 在仅针对 Cordova 应用的 Android App 构建中,通过 HTTPS 调用服务器的 AJAX 调用被阻止。iOS 和桌面浏览器没有此问题。最让人困惑的是,在实际的 Android 浏览器中,HTTPS AJAX 调用将没有问题。

  2. 我验证了自己可以通过 HTTPS 调用知名且值得信任的 URL(例如 https://google.com)以及任何我想尝试的常规 HTTP 调用的 URL。

  3. 这使我相信我的 SSL 证书安装可能没有完全正确,或者来自 PositiveSSL 的便宜证书(约 10 美元)并非普遍受信任,或两者都有可能。

  4. 我的证书已安装在我的 AWS 负载均衡器上,因此我查看了一下如何搞砸它以及 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 Webview 在证书信任方面比 Android 浏览器更为保守。这不完全直观,因为它们应该基本上具有相同的技术。


1
这正是我遇到的问题。安装中间证书解决了问题。我发现这个网站在测试证书方面非常方便;https://ssltools.geotrust.com/checker/views/certCheck.jsp - boodle
@boodle 很好的观点,是的,我也跟进了,并且已经使用这个测试站点进行了验证。 - SoldierOfFortran

6
当请求的URL响应错误或自签名证书时,会出现此问题。在测试或将应用程序分发给朋友时,在AndroidManifest.xml中设置<application android:debuggable="true"...>就足够了——它会自动绕过证书错误。
但Google Play商店不会接受带有android:debuggable="true"的APK。首先需要修复证书。但在此期间,这里是PhoneGap/Cordova 3的解决方法:
  1. In your app package create a subclass for 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. Same for 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. in <Your App Name>.java add an override for 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);
        }
    }
    
< p > Et voilà! SSL错误将被忽略。但是,不要使用错误的证书。尝试先修复它们,仅在没有其他解决方案时使用这个折中办法。


小心。使用此解决方案时,您根本不需要使用SSL,因为任何人都可以在连接中注入错误的SSL证书,而错误会被忽略。 - fastr.de
是的,确实如此。当您仅连接到自己拥有的某些服务器并且配置证书变得非常困难和耗时时,它会有所帮助,就像在我的项目中一样。在它们被修复之前,该应用程序仍应以某种方式工作。 - Ernests Karlsons
1
@ErnestsKarlsons,你能告诉我第一点中的“应用程序包”在哪里吗? - Denis Ramdan

4
另一个同样有效的选择是重新编译底层的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);
    }
}

注意:我知道这不是安全的方法,但当其他方法都失败时,这种方法解决了持续两个月的问题,包括按照证书链安装指南重新安装证书,而且这是我们自己的网站,不是第三方,无论是否有效,它只连接到此服务器。


好观点。然而,我仍会坚持我的答案,因为它更容易实现。 - Ernests Karlsons
我在TSL 1.0证书和Android 5.1.1中遇到了同样的问题。这个方法非常有效!我还发现crosswalk跳过了这个验证。 - atc

1
在我的情况下,问题是缺少中间证书,我必须在我的Web服务器上安装它。当您使用廉价证书时,尤其需要注意这一点。
您可以轻松在线检查您的证书链是否正确,您可以在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

我也遇到了同样的问题,你的解决方案帮了我很多。谢谢! - Eduardo Balbinot

0

您不能使用自签名证书的发布准备好的(PhoneGap)APK。请查看此答案以获取更多信息。

lg

fastrde


感谢!经过数小时的调试,我发现有一个快速修复的可能。请看我的回答。 - Ernests Karlsons

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接