使用 SPDY 版本 3 在 OKHttpClient 版本 3.2.0 中引发的错误
Posted
技术标签:
【中文标题】使用 SPDY 版本 3 在 OKHttpClient 版本 3.2.0 中引发的错误【英文标题】:Error thrown in OKHttpClient version 3.2.0 using SPDY version 3 【发布时间】:2016-07-30 00:05:13 【问题描述】:我有一个应用程序使用:
compile 'com.squareup.okhttp3:okhttp:2.7.0'
compile 'com.squareup.okhttp3:okhttp-urlconnection:3.2.0'
compile 'com.squareup.okio:okio:1.6.0'
compile 'com.squareup.retrofit2:retrofit:2.0.0'
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta3'
并对服务器进行 API REST 调用。在 OKHttpClient 上启用 SPDY 3 时,会抛出错误:
04-08 11:01:22.321 10628-10628/dts W/System.err: java.lang.IllegalArgumentException: protocols doesn't contain http/1.1: [spdy/3.1, h2]
04-08 11:01:22.321 10628-10628/dts W/System.err: at okhttp3.OkHttpClient$Builder.protocols(OkHttpClient.java:672)
我在 OKHttpClient 上找不到正确启用 SPDY/3 的任何内容或错误代码。目标站点已正确配置 SPDY/3。
我已尝试使用 SPDY3、HTTP/2 和 HTTP/1 的所有组合的两种协议配置,应用程序在配置 HTTP/1 时工作,但如果仅启用 SPDY/3 则会引发错误:
okHttpClient = new OkHttpClient.Builder()
// .protocols(Collections.singletonList(Protocol.SPDY_3))
.protocols(Arrays.asList(Protocol.SPDY_3, Protocol.HTTP_2))
.retryOnConnectionFailure(true)
.connectTimeout(25, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool(30, 120, TimeUnit.SECONDS))
.connectionSpecs(Collections.singletonList(spec))
.addInterceptor(new AddCookiesInterceptor())
.addInterceptor(new ReceivedCookiesInterceptor())
.cache(new okhttp3.Cache(cacheLocation, (500 * 1024 * 1024)))
.build();
我知道有人可能有想法,任何帮助将不胜感激。
【问题讨论】:
我确实在文档link 中找到了这个,但对配置 SPDY/3 没有帮助: 参数:协议 - 要使用的协议,按优先顺序排列。该列表必须包含 Protocol.HTTP_1_1。它不能包含 null 或 Protocol.HTTP_1_0。 【参考方案1】:显然,最新版本的 OKHttp 放弃了对 SPDY/3 的支持。仅选择 proto SPDY 或 HTTP2 时会抛出错误代码。文档指出,始终需要 HTTP1 作为 proto 以及之后的其他选择。使用 android 4.1 切换到 HTTP2,您会发现更多连接问题(OKHttp/Android)不支持开箱即用的 TLS1.2,您必须创建自定义 SSLSocketFactory 以覆盖默认值(来自 here ):
public class TLSSocketFactory extends SSLSocketFactory
private SSLSocketFactory delegate;
public TLSSocketFactory() throws KeyManagementException, NoSuchAlgorithmException
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, null, null);
delegate = context.getSocketFactory();
@Override
public String[] getDefaultCipherSuites()
return new String[]"TLSv1.2", "TLS_RSA_WITH_AES_128_CBC_SHA";
@Override
public String[] getSupportedCipherSuites()
return new String[]"TLSv1.2", "TLS_RSA_WITH_AES_128_CBC_SHA";
@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException
return enableTLSOnSocket(delegate.createSocket(s, host, port, autoClose));
@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException
return enableTLSOnSocket(delegate.createSocket(host, port));
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException
return enableTLSOnSocket(delegate.createSocket(host, port, localHost, localPort));
@Override
public Socket createSocket(InetAddress host, int port) throws IOException
return enableTLSOnSocket(delegate.createSocket(host, port));
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException
return enableTLSOnSocket(delegate.createSocket(address, port, localAddress, localPort));
private Socket enableTLSOnSocket(Socket socket)
if (socket != null && (socket instanceof SSLSocket))
((SSLSocket) socket).setEnabledProtocols(new String[]"TLSv1.2");
return socket;
【讨论】:
以上是关于使用 SPDY 版本 3 在 OKHttpClient 版本 3.2.0 中引发的错误的主要内容,如果未能解决你的问题,请参考以下文章
如果服务器实现 spdy/3 而浏览器只支持 spdy/2 会发生啥?