我想弄清楚为什么有时候会出现这个错误
javax.net.ssl.SSLProtocolException:SSL握手已终止: ssl = 0x60d46c90:SSL库失败,通常是协议错误 错误:1409443E:SSL例程:SSL3_READ_BYTES:tlsv1警报不合适 后备(外部/ openssl / ssl / s3_pkt.c:1256 0x60d57f40:0x00000003)
发出此请求的代码:
private <T> void send(final String url, final Map<String, String> args,
final RequestCallback<T> callback, final Parser<T> pParser,
final Context pContext, final HTTP_METHOD method,
final Map<String, String> headers, final BODY_TYPE bodyType) {
final Request.Builder builder = getBuilder(url);
populateHeaders(builder, headers);
final RequestBody body = getBody(args, bodyType);
if(method==HTTP_METHOD.POST) {
builder.post(body);
} else if(method==HTTP_METHOD.GET) {
builder.get();
} else if(method==HTTP_METHOD.PUT) {
builder.put(body);
} else if(method==HTTP_METHOD.PATCH) {
builder.patch(body);
} else {
throw new RuntimeException("Please specify correct method name!");
}
Request request = builder.build();
debugRequest(request, whoCalledThisMethod());
call = client.newCall(request);
call.enqueue(new StandardRequestCallback(pContext, callback, pParser));
}
我发现如果我的应用程序获得此异常,强行关闭它,然后重新启动它,就可以成功完成请求...但是,不久之后,它再次因此SSL异常而失败。
可能出现什么问题?
更新
我制作了一个非常小的测试应用程序,它使用来自okHttp食谱页面https://github.com/square/okhttp/wiki/Recipes的代码,并且我重新编写了SSL握手异常!!
06-27 13:59:08.068 30006-32692/a.b.ssltestapp W/System.err: javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake terminated: ssl=0x60068d10: Failure in SSL library, usually a protocol error
06-27 13:59:08.068 30006-32692/a.b.ssltestapp W/System.err: error:1409443E:SSL routines:SSL3_READ_BYTES:tlsv1 alert inappropriate fallback (external/openssl/ssl/s3_pkt.c:1256 0x6006e6b0:0x00000003)
06-27 13:59:08.078 30006-32692/a.b.ssltestapp W/System.err: at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:568)
06-27 13:59:08.078 30006-32692/a.b.ssltestapp W/System.err: at okhttp3.internal.io.RealConnection.connectTls(RealConnection.java:188)
06-27 13:59:08.078 30006-32692/a.b.ssltestapp W/System.err: at okhttp3.internal.io.RealConnection.connectSocket(RealConnection.java:145)
06-27 13:59:08.078 30006-32692/a.b.ssltestapp W/System.err: at okhttp3.internal.io.RealConnection.connect(RealConnection.java:108)
06-27 13:59:08.078 30006-32692/a.b.ssltestapp W/System.err: at okhttp3.internal.http.StreamAllocation.findConnection(StreamAllocation.java:188)
06-27 13:59:08.088 30006-32692/a.b.ssltestapp W/System.err: at okhttp3.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:127)
06-27 13:59:08.088 30006-32692/a.b.ssltestapp W/System.err: at okhttp3.internal.http.StreamAllocation.newStream(StreamAllocation.java:97)
06-27 13:59:08.088 30006-32692/a.b.ssltestapp W/System.err: at okhttp3.internal.http.HttpEngine.connect(HttpEngine.java:289)
06-27 13:59:08.088 30006-32692/a.b.ssltestapp W/System.err: at okhttp3.internal.http.HttpEngine.sendRequest(HttpEngine.java:241)
06-27 13:59:08.088 30006-32692/a.b.ssltestapp W/System.err: at okhttp3.RealCall.getResponse(RealCall.java:240)
06-27 13:59:08.088 30006-32692/a.b.ssltestapp W/System.err: at okhttp3.RealCall$ApplicationInterceptorChain.proceed(RealCall.java:198)
06-27 13:59:08.088 30006-32692/a.b.ssltestapp W/System.err: at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:160)
06-27 13:59:08.098 30006-32692/a.b.ssltestapp W/System.err: at okhttp3.RealCall.access$100(RealCall.java:30)
06-27 13:59:08.098 30006-32692/a.b.ssltestapp W/System.err: at okhttp3.RealCall$AsyncCall.execute(RealCall.java:127)
06-27 13:59:08.098 30006-32692/a.b.ssltestapp W/System.err: at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:33)
06-27 13:59:08.098 30006-32692/a.b.ssltestapp W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
06-27 13:59:08.098 30006-32692/a.b.ssltestapp W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
06-27 13:59:08.098 30006-32692/a.b.ssltestapp W/System.err: at java.lang.Thread.run(Thread.java:841)
06-27 13:59:08.098 30006-32692/a.b.ssltestapp W/System.err: Suppressed: javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake terminated: ssl=0x60068d10: Failure in SSL library, usually a protocol error
06-27 13:59:08.098 30006-32692/a.b.ssltestapp W/System.err: error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure (external/openssl/ssl/s3_pkt.c:1256 0x5ff9aa20:0x00000003)
06-27 13:59:08.108 30006-32692/a.b.ssltestapp W/System.err: ... 18 more
06-27 13:59:08.108 30006-32692/a.b.ssltestapp W/System.err: Caused by: javax.net.ssl.SSLProtocolException: SSL handshake terminated: ssl=0x60068d10: Failure in SSL library, usually a protocol error
06-27 13:59:08.108 30006-32692/a.b.ssltestapp W/System.err: error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure (external/openssl/ssl/s3_pkt.c:1256 0x5ff9aa20:0x00000003)
06-27 13:59:08.118 30006-32692/a.b.ssltestapp W/System.err: at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
06-27 13:59:08.118 30006-32692/a.b.ssltestapp W/System.err: at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:486)
06-27 13:59:08.118 30006-32692/a.b.ssltestapp W/System.err: ... 17 more
06-27 13:59:08.118 30006-32692/a.b.ssltestapp W/System.err: Caused by: javax.net.ssl.SSLProtocolException: SSL handshake terminated: ssl=0x60068d10: Failure in SSL library, usually a protocol error
06-27 13:59:08.118 30006-32692/a.b.ssltestapp W/System.err: error:1409443E:SSL routines:SSL3_READ_BYTES:tlsv1 alert inappropriate fallback (external/openssl/ssl/s3_pkt.c:1256 0x6006e6b0:0x00000003)
06-27 13:59:08.118 30006-32692/a.b.ssltestapp W/System.err: at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
06-27 13:59:08.118 30006-32692/a.b.ssltestapp W/System.err: at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:486)
06-27 13:59:08.118 30006-32692/a.b.ssltestapp W/System.err: ... 17 more
答案 0 :(得分:2)
这不是解决方案,但在涉及上述问题时会提供一些网络调试。
如果上面问题1940中提到的网络接口存在问题,那么您可以通过实现Dns接口以及socketFactory来解决该问题。它可能你得到两条DNS记录,一条适合你而另一条不适用,重启后它就会改变。
尝试通过添加调试查看
的结果来确认 Dns.SYSTEM.lookup(hostname)
NetworkInterface.getByInetAddress(address)
NetworkInterface.getNetworkInterfaces()
<强>更新强>
Callback.OnFailure中的代码来调试此问题:
@Override
public void onFailure(final Call call, final IOException e) {
if (call.isCanceled()) {
SLog.w(TAG, "onFailure: Canceled");
return;
}
if(e instanceof SSLException){
try {
Log.d(getClass().getSimpleName(), "Checking DNS hosts ... ");
List<InetAddress> list = Dns.SYSTEM.lookup(call.request().url().host());
Log.d(getClass().getSimpleName(), "Number of Entries: "+list.size());
for (InetAddress address : list) {
Log.d(getClass().getSimpleName(), address.toString());
}
Log.d(getClass().getSimpleName(), "End of Checking DNS hosts");
} catch (UnknownHostException e1) {
e1.printStackTrace();
}
try {
Log.d(getClass().getSimpleName(), "Checking Network Interfaces ... ");
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
ArrayList<NetworkInterface> list = Collections.list(interfaces);
Log.d(getClass().getSimpleName(), "Number of Entries: "+list.size());
for(NetworkInterface netintface : list) {
Log.d(getClass().getSimpleName(), netintface.toString());
List<InterfaceAddress> listaddresses = netintface.getInterfaceAddresses();
Log.d(getClass().getSimpleName(), " Number of Interface Addresses: "+listaddresses.size());
for (InterfaceAddress infcaddress : listaddresses) {
Log.d(getClass().getSimpleName(), " > InterfaceAddress : "+infcaddress.toString());
}
}
Log.d(getClass().getSimpleName(), "End of Checking Network Interfaces");
} catch (SocketException e1) {
e1.printStackTrace();
}
}
}
来自上面代码的DEBUG OUTPUT
06-21 11:43:19.495 12890-12890/com.app.stg D/[StandardRequest]: ->
------------- Request -------------
********** METHOD sendRequest() **********
GET
-----------------------------------
06-21 11:43:24.330 12890-21401/com.app.stg D/StandardRequestCallback: Checking DNS hosts ...
06-21 11:43:24.450 12890-21401/com.app.stg D/StandardRequestCallback: Number of Entries: 8
06-21 11:43:24.450 12890-21401/com.app.stg D/StandardRequestCallback: arc.stg.issa.sainsburys.co.uk/52.85.69.145
06-21 11:43:24.450 12890-21401/com.app.stg D/StandardRequestCallback: arc.stg.issa.sainsburys.co.uk/52.85.69.20
06-21 11:43:24.450 12890-21401/com.app.stg D/StandardRequestCallback: arc.stg.issa.sainsburys.co.uk/52.85.69.185
06-21 11:43:24.450 12890-21401/com.app.stg D/StandardRequestCallback: arc.stg.issa.sainsburys.co.uk/52.85.69.84
06-21 11:43:24.450 12890-21401/com.app.stg D/StandardRequestCallback: arc.stg.issa.sainsburys.co.uk/52.85.69.249
06-21 11:43:24.450 12890-21401/com.app.stg D/StandardRequestCallback: arc.stg.issa.sainsburys.co.uk/52.85.69.52
06-21 11:43:24.450 12890-21401/com.app.stg D/StandardRequestCallback: arc.stg.issa.sainsburys.co.uk/52.85.69.159
06-21 11:43:24.450 12890-21401/com.app.stg D/StandardRequestCallback: arc.stg.issa.sainsburys.co.uk/52.85.69.246
06-21 11:43:24.460 12890-21401/com.app.stg D/StandardRequestCallback: End of Checking DNS hosts
06-21 11:43:24.460 12890-21401/com.app.stg D/StandardRequestCallback: Checking Network Interfaces ...
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback: Number of Entries: 4
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback: [lo][1][/::1%1%1][/127.0.0.1]
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback: Number of Interface Addresses: 2
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback: > InterfaceAddress : /::1%1%1/128 [null]
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback: > InterfaceAddress : /127.0.0.1/8 [null]
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback: [sit0][2]
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback: Number of Interface Addresses: 0
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback: [wlan0][4][/fe80::4283:deff:fe94:b0ff%wlan0%4][/172.24.90.253]
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback: Number of Interface Addresses: 2
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback: > InterfaceAddress : /fe80::4283:deff:fe94:b0ff%wlan0%4/64 [null]
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback: > InterfaceAddress : /172.24.90.253/19 [/172.24.95.255]
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback: [ip6tnl0][3]
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback: Number of Interface Addresses: 0
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback: End of Checking Network Interfaces
06-21 11:43:24.480 12890-12890/com.app.stg D/JS-[LauncherActivity]: ErrorReport{type='SSLHandshakeException'}
答案 1 :(得分:0)
我找到了一个解决方法 - 基本上你创建了一个OkHttpClient的新实例!请参阅下面的代码......
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.io.IOException;
import javax.net.ssl.SSLException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class ActivityMain extends AppCompatActivity
{
private Button buttonStart;
private Button buttonStop;
private TextView textView;
private Handler handler;
private Integer mCount = 0;
private Boolean mQuit;
private OkHttpClient client = new OkHttpClient();
private Runnable mRunnable;
final int DELAY_SUBSEQUENT_REQUEST = 5000;//5sec
final String REQUEST_URL = "https://whatever.com/url/to/test";
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handler = new Handler();
buttonStart = (Button)findViewById(R.id.buttonstart);
buttonStop = (Button)findViewById(R.id.buttonstop);
textView = (TextView)findViewById(R.id.textview);
mRunnable = new Runnable() {
@Override
public void run() {
if (!mQuit) {
mCount++;
textView.setText(String.valueOf(mCount));
// do the GET call here
RequestGet();
}
}
};
buttonStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
buttonStart.setEnabled(false);
triggerDelayedSslRequest(0);
mQuit = false;
}
});
buttonStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
buttonStart.setEnabled(true);
mQuit = true;
handler.removeCallbacks(mRunnable);
mCount = 0;
}
});
}
private void triggerDelayedSslRequest(int delay)
{
handler.postDelayed(mRunnable, delay);
}
private void RequestGet()
{
Request request = new Request.Builder()
.url(REQUEST_URL)
.build();
// NOTE: onFailure and onResponse are not on the main thread
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, final IOException e) {
// the SSL error is trapped here
e.printStackTrace();
handler.post(new Runnable() {
@Override
public void run() {
textView.setText(e.getMessage());
buttonStart.setEnabled(true);
}
});
// Crazy "fix" for SSLException
if(e instanceof SSLException) {
client = new OkHttpClient();
}
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
if (!response.isSuccessful())
{
handler.post(new Runnable() {
@Override
public void run() {
textView.setText("Error Response: "+response.toString());
}
});
} else {
System.out.println(response.body().string());
}
// schedule the next GET request
triggerDelayedSslRequest(DELAY_SUBSEQUENT_REQUEST);
}
});
}
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="a.b.ssltestapp.ActivityMain">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start"
android:id="@+id/buttonstart"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Stop"
android:id="@+id/buttonstop"
android:layout_below="@+id/buttonstart"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/textview"
android:layout_marginTop="100dp"
android:text="Press START to test SSL"
android:gravity="center"
android:layout_below="@+id/buttonstop"
android:layout_centerHorizontal="true"/>
</RelativeLayout>
然而,这个修复非常不方便。
总结修复:
创建一个新的OkHttpClient对象是什么让SSL握手再次运作?