OKHttp Android没有通过http2 alpn连接到nginx

Posted

技术标签:

【中文标题】OKHttp Android没有通过http2 alpn连接到nginx【英文标题】:OKHttp Android not connecting to nginx via http2 alpn 【发布时间】:2016-08-12 03:47:48 【问题描述】:

我有一个使用以下库的 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'

我有 nginx(版本 1.9.14) 用 OpenSSL 编译(版本 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 都会导致 HTTP/2 连接显示在 SSL 日志和 HTTP/2 chrome 插件中。假设在 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 套接字工厂,以在

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 链接]How to use http/2 with Okhttp on Android devices? 有一条评论建议使用码头,但仅限于桌面使用,不是安卓使用。

更新 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.4.4: TLSv1.2 ECDHE-RSA-AES128-SHA - 5.1。 1:TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256-6.0:TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256-7.0: TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256 - Chrome/FireFox:TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256。只有 Chrome/FireFox 和“7.0(N)”使用 HTTP/2 连接。 这方面有什么更新吗?您是否能够在 4.4.4 上获得 http2 或者您是否会选择其他替代方案? 我现在开始做其他事情,但我想很快再访问这里。我明天可能会看看,看看我可以用任何更新的库做什么。 OkHttpClient.Builder“sslSocketFactory”中似乎有一个新的(扩展的)方法。原始方法(已弃用)仅需要 sslSocketFactory,但新方法需要 sslSocketFactory 和 X509TrustFactory。这里可能有一些东西,但如果这有任何影响,我将不得不调查下一个构建周期。我有限的理解是,Android( 【参考方案1】:

根据 swankjesse,

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

Don't use broken ALPN on Android 4.4

【讨论】:

真正的问题是关于如何让 HTTP2 在

以上是关于OKHttp Android没有通过http2 alpn连接到nginx的主要内容,如果未能解决你的问题,请参考以下文章

Android开发技术周报176学习记录

OkHttp学习 - POM 文件

OkHttp学习 - POM 文件

Android OkHttp3简介和使用详解

奇怪的知识: okhttp 是如何支持 Http2 的?

在okhttp中使用http2时,为啥对同一主机的多个请求不只使用一个connectoin