0

我有一个应用程序使用:

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

我知道有人可能有想法,任何帮助将不胜感激。

4

1 回答 1

1

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

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

}

于 2016-04-08T20:47:10.977 回答