2

我有一个使用以下库的 android 应用程序(4.4.4+):

compile 'com.squareup.okhttp3:okhttp:3.2.0'
compile 'com.squareup.okhttp3:okhttp-urlconnection:3.2.0'
compile 'com.squareup.okio:okio:1.7.0'

我使用 OpenSSL 编译的 nginx(版本 1.9.14)(版本 1.0.2g 源代码编译)在 centOS 7 上使用 nginx -V 确认了 openSSL 的使用。为反向代理启用了 nginx http2 的配置:

 server {
            listen  443 ssl http2;
            ssl     on;
            server_name     mobile.site.com;
            ssl_certificate         /etc/pki/tls/certs/start_cert.pem;
            ssl_certificate_key     /etc/pki/tls/certs/start_cert.key;
            proxy_cache     one;
            underscores_in_headers  on;
            access_log      /var/log/nginx/ssl.log ssl_custom;
            location / {
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Forwarded-For $remote_addr;
                    proxy_set_header Host $host;
                    proxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment;
                    proxy_pass https://10.10.1.31:443;
            }
    }

在服务器上运行命令:

echo | openssl s_client -alpn h2 -connect

回报:

No client certificate CA names sent
Peer signing digest: SHA512
Server Temp Key: ECDH, P-256, 256 bits
---
SSL handshake has read 3718 bytes and written 442 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 4096 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
ALPN protocol: h2

从任何现代浏览器浏览 API URL 会导致在 SSL 日志和 HTTP/2 chrome 插件中显示 HTTP/2 连接。假设在 nginx/OpenSSL 中正确配置了 HTTP/2。

Android OKHttp 客户端拒绝 HTTP/2:

            ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
                    .tlsVersions(TlsVersion.TLS_1_2)
                    .build();
            okHttpClient = new OkHttpClient.Builder()
                    .followSslRedirects(true)
                    .protocols(Arrays.asList(Protocol.HTTP_2, Protocol.HTTP_1_1))
                    .connectionSpecs(Collections.singletonList(spec))
                    .sslSocketFactory(new TLSSocketFactory((SSLSocketFactory) TLSSocketFactory.getDefault()))
                    .retryOnConnectionFailure(true)
                    .connectTimeout(25, TimeUnit.SECONDS)
                    .connectionPool(new ConnectionPool(30, 120, TimeUnit.SECONDS))
                    .addInterceptor(new AddCookiesInterceptor())
                    .addInterceptor(new ReceivedCookiesInterceptor())
                    .build();

我编写了一个自定义 TLS 套接字工厂,以在 <= Android 4.4.4 上启用 TLS 1.2。

TLSv1.2 确实可以使用这个自定义套接字工厂在 4.4.4+ 上运行,但我也尝试在 5.0+ 上运行,无论是否使用自定义套接字工厂,都没有 HTTP/2 运气。

HTTP/2 在 kit-kat、棒棒糖和棉花糖上失败,但在“N”开发者预览版(又名纽约芝士蛋糕)上工作。不会抛出任何错误,只会以 HTTP/1.1 连接。我很难找到任何与 OKhttp 和 HTTP/2 相关的文章,大多数帮助问题/帖子只是说使用 ALPN,但没有资源来详细说明其用法。OkHTTP 文档并不清楚 HTTP/2 的使用和部署实践,但主页上说它支持它。任何帮助或专家指导将不胜感激,即使只是朝着正确的方向轻推也会是一个巨大的帮助。如果我错过了任何可能在此过程中提供帮助的内容,请告诉我,提前致谢!

更新 1:我发现了一个与此相关的 SO 问题,答案非常模糊:[SO 链接]如何在 Android 设备上将 http/2 与 Okhttp 一起使用?有一条评论建议使用码头,但仅限于桌面使用,而不是 Android 使用。

更新 2:本文显示 ALPN 已在 Android 4.4 中启用:https ://github.com/http2/http2-spec/wiki/ALPN-Status

更新 3:能够使用 +5.0 连接 HTTP/2,但不能使用 4.4.4。我不需要低于 4.4.4,因为内部目标设备是 http/2 的关注点,它们运行 4.4.4。我能够更新应用程序以使用 Google Play Services 安全协议作为 OKHttp 套接字连接,但我们使用的 4.4.4 设备未启用 Google,因此我无法在这些设备上使用 PlayServices 安全套接字。

4

1 回答 1

0

根据 swankjesse 的说法,

下一步:不要在 Android 4.4 及更早版本上使用 ALPN;它在那里坏了。为之前稳定的 Android 版本恢复 NPN。

不要在 Android 4.4 上使用损坏的 ALPN

于 2017-05-16T03:20:59.863 回答