使用SPDY版本3在OKHttpClient版本3.2.0中引发错误

时间:2016-04-08 16:15:10

标签: android rest spdy okhttp3

我有一个使用的应用程序:

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和SPDY的所有组合的两种协议配置。 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();
        }

我知道有人可能有想法,任何帮助都会非常感激。

1 个答案:

答案 0 :(得分:1)

显然,最新版本的OKHttp放弃了对SPDY / 3的支持。选择proto SPDY或HTTP2时会抛出错误代码。该文档指出HTTP1始终需要作为proto,以及之后的其他选择。使用Android 4.1切换到HTTP2,你会发现更多的连接问题(OKHttp / Android)不支持开箱即用的TLS1.2,你必须创建一个自定义的SSLSocketFactory来覆盖默认值(来自{{3 }}):

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;
}

}