【问题标题】:Retrofit request is not working on pre Lollipop devices改造请求不适用于预棒棒糖设备
【发布时间】:2019-11-18 19:43:00
【问题描述】:

我想从 URL 获取 html 页面源。 Retrofit 正在后期棒棒糖设备上完成这项工作。但在棒棒糖之前的设备上,它会给出不受支持的协议错误。

代码:

private static final String TAG = "TESTTESTTESTTEST";
private static String url = "https://www.hepsiburada.com/lassa-235-65r17-108h-xl-competush-" +
            "l-p-OTLST216410?magaza=LastikArt%C4%B1&utm_source=pc&utm_medium=cimri&utm_campaign" +
            "=c&utm_content=c&utm_term=5083&wt_pc=cimri.c.5083.pc/";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Retrofit retrofit = new Retrofit.Builder()
            .addConverterFactory(ScalarsConverterFactory.create())
            .baseUrl("https://www.google.com/")
            .build();

    IGetHtml iGetHtml = retrofit.create(IGetHtml.class);
    Call<String> stringCall = iGetHtml.getHtml(url);
    stringCall.enqueue(new Callback<String>() {
        @Override
        public void onResponse(Call<String> call, Response<String> response) {
            if (response.isSuccessful()) {
                String responseString = response.body();
                Log.e(TAG, "onResponse: " + response.body());
            }
        }

        @Override
        public void onFailure(Call<String> call, Throwable t) {
            Log.e(TAG, "onFailure: " + t);
        }
    });


}

错误

E/NativeCrypto:握手期间出现未知错误 07-09 12:23:57.606

E/TESTTESTTESTTEST:onFailure:javax.net.ssl.SSLHandshakeException:javax.ne.ssl.SSLProtocolException: SSL 握手中止:ssl=0x7cf6f320:SSL 库失败,通常 协议错误错误:14077102:SSL 例程:SSL23_GET_SERVER_HELLO:不支持的协议 (外部/openssl/ssl/s23_clnt.c:714 0x7a084894:0x00000000)

【问题讨论】:

标签: android ssl retrofit retrofit2


【解决方案1】:

我用这个解决方案解决了我的错误。

一切都和我在问题中写的一样,除了这个变化。

将此类添加到您的项目中。

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

    @Override
    public String[] getSupportedCipherSuites() {
        return delegate.getSupportedCipherSuites();
    }

    @Override
    public Socket createSocket() throws IOException {
        return enableTLSOnSocket(delegate.createSocket());
    }

    @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.1", "TLSv1.2"});
        }
        return socket;
    }
}

然后onCreate方法改成这个。

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        OkHttpClient client = new OkHttpClient();
        try {
            client = new OkHttpClient.Builder()
                    .sslSocketFactory(new TLSSocketFactory())
                    .build();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://www.google.com/")
                .client(client)
                .addConverterFactory(ScalarsConverterFactory.create())
                .build();

        IGetHtml iGetHtml = retrofit.create(IGetHtml.class);
        Call<String> stringCall = iGetHtml.getHtml(url);
        stringCall.enqueue(new Callback<String>() {
            @Override
            public void onResponse(Call<String> call, Response<String> response) {
                if (response.isSuccessful()) {
                    Log.e(TAG, "onResponse: " + response.headers());
                }
            }

            @Override
            public void onFailure(Call<String> call, Throwable t) {
                Log.e(TAG, "onFailure: " + t);
            }
        });


    }

【讨论】:

    【解决方案2】:

    这不是因为 Retrofit,而是因为低版本的 Android 没有启用 TLS 和 SSL 支持。

    https://developer.android.com/reference/javax/net/ssl/SSLSocket

    您可以通过在您的应用中检查 Google Play 服务更新来在 Android 4.1 - 4.4 版本上启用 TLS。您可以在 Android 中单独搜索 ProviderInstaller。

    如果它只是一个 html 页面,我建议使用

    在外部浏览器中打开它
    new Intent(Intent.ACTION_VIEW, Uri.parse("your url"));
    

    【讨论】:

    • 我进行了研究,但找不到适用的解决方案来在 Lollipop 之前的设备上启用 tls。如何在我的代码上简单地启用 tls?
    • 我在您的指导下解决了我的错误。非常感谢。
    猜你喜欢
    • 2016-07-04
    • 2015-01-14
    • 2018-12-07
    • 2016-05-19
    • 2015-02-25
    • 1970-01-01
    • 2016-12-06
    • 1970-01-01
    • 2016-01-20
    相关资源
    最近更新 更多