我已经在SO上发表过类似的帖子,指出了类似的问题。 就我而言,我尝试在API级28的Nexus 6p模拟器上运行。
此实现适用于Volley HurlStack,但不适用于OkHttp3 HttpStack。因此,我确定服务器端没有问题,但OkHttp方面没有问题。不知道我在这里想念什么。任何线索将不胜感激。预先感谢!
PS :我正准备远离Volley。这只是使用okHttp进行测试,以便更轻松地进行迁移。
排球工作实施如下:
import android.annotation.SuppressLint;
import android.util.Base64;
import com.abc.test.core.network.Tls12SocketFactory;
import com.android.volley.toolbox.HurlStack;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import timber.log.Timber;
public class VolleyHurlStack extends HurlStack {
private final Boolean enablePinning;
VolleyHurlStack(Boolean enablePinning) {
this.enablePinning = enablePinning;
}
@Override
protected HttpURLConnection createConnection(URL url) throws IOException {
HttpsURLConnection httpsURLConnection = (HttpsURLConnection) super.createConnection(url);
try {
httpsURLConnection.setSSLSocketFactory(getSSLSocketFactory());
httpsURLConnection.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
try {
return validatePinning(session.getPeerCertificates());
} catch (SSLPeerUnverifiedException e) {
Timber.e(e);
}
return false;
}
});
} catch (Exception e) {
Timber.e(e);
}
return httpsURLConnection;
}
private SSLSocketFactory getSSLSocketFactory() {
SSLContext sc;
SSLSocketFactory sslSocketFactory = null;
try {
sc = SSLContext.getInstance("TLSv1.1");
if (sc != null) {
sc.init(null, getAllTrustManagers(), new SecureRandom());
sslSocketFactory = new Tls12SocketFactory(sc.getSocketFactory());
} else {
Timber.e("SSLContext is null");
}
} catch (NoSuchAlgorithmException | KeyManagementException e) {
Timber.e(e);
}
return sslSocketFactory;
}
private TrustManager[] getAllTrustManagers() {
return new TrustManager[]{getX509TrustManager()};
}
private X509TrustManager getX509TrustManager() {
return new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
@SuppressLint("TrustAllX509TrustManager")
@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
@SuppressLint("TrustAllX509TrustManager")
@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
};
}
public boolean validatePinning(Certificate[] certificate) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
for (Certificate cert : certificate) {
byte[] publicKey = cert.getPublicKey().getEncoded();
md.update(publicKey, 0, publicKey.length);
String pin = Base64.encodeToString(md.digest(), Base64.NO_WRAP);
for (String validPin : validPins) {
if (validPin.contains(pin)) {
Timber.d("validatePinning successful");
return true;
}
}
}
} catch (NoSuchAlgorithmException e) {
Timber.e(e);
}
return false;
}
}
非正常的OkHttp实现如下:
import android.annotation.SuppressLint;
import android.util.Base64;
import com.abc.test.core.network.Tls12SocketFactory;
import com.android.volley.AuthFailureError;
import com.android.volley.Header;
import com.android.volley.Request;
import com.android.volley.toolbox.BaseHttpStack;
import com.android.volley.toolbox.HttpResponse;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import okhttp3.Call;
import okhttp3.ConnectionSpec;
import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import timber.log.Timber;
public class OkHttp3Stack extends BaseHttpStack {
public OkHttp3Stack() {
}
private static void setConnectionParametersForRequest(okhttp3.Request.Builder builder, Request<?> request)
throws AuthFailureError {
switch (request.getMethod()) {
case Request.Method.DEPRECATED_GET_OR_POST:
// Ensure backwards compatibility. Volley assumes a request with a null body is a GET.
byte[] postBody = request.getBody();
if (postBody != null) {
builder.post(RequestBody.create(MediaType.parse(request.getBodyContentType()), postBody));
}
break;
case Request.Method.GET:
builder.get();
break;
case Request.Method.DELETE:
builder.delete(createRequestBody(request));
break;
case Request.Method.POST:
builder.post(createRequestBody(request));
break;
case Request.Method.PUT:
builder.put(createRequestBody(request));
break;
case Request.Method.HEAD:
builder.head();
break;
case Request.Method.OPTIONS:
builder.method("OPTIONS", null);
break;
case Request.Method.TRACE:
builder.method("TRACE", null);
break;
case Request.Method.PATCH:
builder.patch(createRequestBody(request));
break;
default:
throw new IllegalStateException("Unknown method type.");
}
}
private static RequestBody createRequestBody(Request r) throws AuthFailureError {
final byte[] body = r.getBody();
if (body == null) {
return null;
}
return RequestBody.create(MediaType.parse(r.getBodyContentType()), body);
}
@Override
public HttpResponse executeRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError {
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
int timeoutMs = request.getTimeoutMs();
clientBuilder.connectTimeout(timeoutMs, TimeUnit.MILLISECONDS);
clientBuilder.readTimeout(timeoutMs, TimeUnit.MILLISECONDS);
clientBuilder.writeTimeout(timeoutMs, TimeUnit.MILLISECONDS);
okhttp3.Request.Builder okHttpRequestBuilder = new okhttp3.Request.Builder();
okHttpRequestBuilder.url(request.getUrl());
Map<String, String> headers = request.getHeaders();
for (final String name : headers.keySet()) {
okHttpRequestBuilder.addHeader(name, headers.get(name));
}
for (final String name : additionalHeaders.keySet()) {
okHttpRequestBuilder.addHeader(name, additionalHeaders.get(name));
}
setConnectionParametersForRequest(okHttpRequestBuilder, request);
clientBuilder.sslSocketFactory(getSSLSocketFactory(), getX509TrustManager());
clientBuilder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
try {
return validatePinning(session.getPeerCertificates());
} catch (SSLPeerUnverifiedException e) {
Timber.e(e);
}
return false;
}
});
ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.allEnabledTlsVersions()
.allEnabledCipherSuites()
.build();
clientBuilder.connectionSpecs(Collections.singletonList(spec));
clientBuilder.retryOnConnectionFailure(true);
OkHttpClient client = clientBuilder.build();
okhttp3.Request okHttpRequest = okHttpRequestBuilder.build();
Call okHttpCall = client.newCall(okHttpRequest);
Response okHttpResponse = okHttpCall.execute();
int code = okHttpResponse.code();
ResponseBody body = okHttpResponse.body();
InputStream content = body == null ? null : body.byteStream();
int contentLength = body == null ? 0 : (int) body.contentLength();
List<Header> responseHeaders = mapHeaders(okHttpResponse.headers());
return new HttpResponse(code, responseHeaders, contentLength, content);
}
private List<Header> mapHeaders(Headers responseHeaders) {
List<Header> headers = new ArrayList<>();
for (int i = 0, len = responseHeaders.size(); i < len; i++) {
final String name = responseHeaders.name(i), value = responseHeaders.value(i);
if (name != null) {
headers.add(new Header(name, value));
}
}
return headers;
}
private SSLSocketFactory getSSLSocketFactory() {
SSLContext sc;
SSLSocketFactory sslSocketFactory = null;
try {
sc = SSLContext.getInstance("TLSv1.1");
if (sc != null) {
sc.init(null, getAllTrustManagers(), new SecureRandom());
sslSocketFactory = new Tls12SocketFactory(sc.getSocketFactory());
} else {
Timber.e("SSLContext is null");
}
} catch (NoSuchAlgorithmException | KeyManagementException e) {
Timber.e(e);
}
return sslSocketFactory;
}
private TrustManager[] getAllTrustManagers() {
return new TrustManager[]{getX509TrustManager()};
}
private X509TrustManager getX509TrustManager() {
return new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
@SuppressLint("TrustAllX509TrustManager")
@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
@SuppressLint("TrustAllX509TrustManager")
@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
};
}
private boolean validatePinning(Certificate[] certificate) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
for (Certificate cert : certificate) {
byte[] publicKey = cert.getPublicKey().getEncoded();
md.update(publicKey, 0, publicKey.length);
String pin = Base64.encodeToString(md.digest(), Base64.NO_WRAP);
for (String validPin : validPins) {
if (validPin.contains(pin)) {
Timber.d("validatePinning successful");
return true;
}
}
}
} catch (NoSuchAlgorithmException e) {
Timber.e(e);
}
return false;
}
}
答案 0 :(得分:0)
显然,传递默认用户代理值存在问题,该值在后端被阻止
与okhttp一起传递的User-Agent值为:okhttp 开始传递自定义用户代理值,问题已解决。
它没有作为okhttpInterceptor的一部分记录下来,因此跟踪两个请求中的差异花费了很多时间。不要期望用户代理会成为罪魁祸首。