版权声明:本文为延成原创文章,转载请标明出处
首先导包
implementation 'com.squareup.okhttp3:okhttp:3.12.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.12.0'
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
implementation 'com.squareup.retrofit2:converter-scalars:2.5.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'
Retrofit工具类的封装RetrofitHelper.calss
/**
* @author Mr.release
* @create 2019/3/29
* @Describe
*/
public class RetrofitHelper {
private static final String HEAD_LINE_NEWS = "T1348647909107";
private static OkHttpClient.Builder builder;
static {
initOkHttpClient();
}
private static void initOkHttpClient() {
if (builder == null) {
synchronized (RetrofitHelper.class) {
if (builder == null) {
HttpsSSLUtils.SSLParams sslParams = HttpsSSLUtils.getSslSocketFactory();
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
if (BuildConfig.DEBUG) {
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
} else {
interceptor.setLevel(HttpLoggingInterceptor.Level.NONE);
}
Cache cache = new Cache(new File(App.getInstance().getCacheDir(), "HttpCache"), 1024 * 1024 * 10);
builder = new OkHttpClient.Builder()
.cache(cache)
.addInterceptor(interceptor)
.addInterceptor(new headerIntercepteor())
.addNetworkInterceptor(new CacheInterceptor())
.sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager)
.retryOnConnectionFailure(true)
.connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS);
}
}
}
}
private static <T> T createApi(String baseUrl, Class<T> cls) {
Retrofit retrofit = new Retrofit.Builder()
.client(builder.build())
.baseUrl(baseUrl)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
// .addConverterFactory(StringConverterFactory.create())
.build();
return retrofit.create(cls);
}
private static NewsServiceApi createNewsServiceApi() {
return createApi(BaseURL.NEWS_HOST, NewsServiceApi.class);
}
private static RecommendServiceApi createRecommendServiceApi() {
return createApi(BaseURL.RECOMMEND_HOST, RecommendServiceApi.class);
}
/**
* 打印返回的json数据拦截器
*/
private static class headerIntercepteor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
final Request request = chain.request();
Buffer requestBuffer = new Buffer();
if (request == null)
throw new RuntimeException("Request返回值不能为空");
RequestBody requestBody = request.body();
if (requestBody != null)
requestBody.writeTo(requestBuffer);
else
Logger.d("request.body() == null");
//打印url信息
Logger.w(request.url() + (requestBody != null ? "?" + _parseParams(requestBody, requestBuffer) : ""));
final Response response = chain.proceed(request);
if (response == null) {
throw new RuntimeException("Response返回值不能为空");
}
return response;
}
}
@NonNull
private static String _parseParams(RequestBody body, Buffer requestBuffer) throws UnsupportedEncodingException {
if (body.contentType() != null && !body.contentType().toString().contains("multipart")) {
return URLDecoder.decode(requestBuffer.readUtf8(), "UTF-8");
}
return "null";
}
private static class UserAgentInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
Request requestWithUserAgent = originalRequest.newBuilder()
.removeHeader("User-Agent")
.addHeader("User-Agent", BaseURL.COMMON_UA_STR)
.build();
return chain.proceed(requestWithUserAgent);
}
}
private static class CacheInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
// 有网络时 设置缓存超时时间1个小时
int maxAge = 60 * 60;
// 无网络时,设置超时为1周
int maxStale = 60 * 60 * 24 * 7;
Request request = chain.request();
if (CommonUtil.isNetworkAvailable(App.getInstance())) {
//有网络时只从网络获取
request = request.newBuilder().cacheControl(CacheControl.FORCE_NETWORK).build();
} else {
//无网络时只从缓存中读取
request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();
}
Response response = chain.proceed(request);
if (CommonUtil.isNetworkAvailable(App.getInstance())) {
response = response.newBuilder()
.removeHeader("Pragma")
.header("Cache-Control", "public, max-age=" + maxAge)
.build();
} else {
response = response.newBuilder()
.removeHeader("Pragma")
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.build();
}
return response;
}
}
HttpsSSLUtils.calss
/**
* @author Mr.release
* @create 2019/3/29
* @Describe
*/
public class HttpsSSLUtils {
public static class SSLParams {
public SSLSocketFactory sSLSocketFactory;
public X509TrustManager trustManager;
}
public static SSLParams getSslSocketFactory() {
return getSslSocketFactoryBase(null, null, null);
}
/**
* https单向认证
* 可以额外配置信任服务端的证书策略,否则默认是按CA证书去验证的,若不是CA可信任的证书,则无法通过验证
*/
public static SSLParams getSslSocketFactory(X509TrustManager trustManager) {
return getSslSocketFactoryBase(trustManager, null, null);
}
/**
* https单向认证
* 用含有服务端公钥的证书校验服务端证书
*/
public static SSLParams getSslSocketFactory(InputStream... certificates) {
return getSslSocketFactoryBase(null, null, null, certificates);
}
/**
* https双向认证
* bksFile 和 password -> 客户端使用bks证书校验服务端证书
* certificates -> 用含有服务端公钥的证书校验服务端证书
*/
public static SSLParams getSslSocketFactory(InputStream bksFile, String password, InputStream... certificates) {
return getSslSocketFactoryBase(null, bksFile, password, certificates);
}
/**
* https双向认证
* bksFile 和 password -> 客户端使用bks证书校验服务端证书
* X509TrustManager -> 如果需要自己校验,那么可以自己实现相关校验,如果不需要自己校验,那么传null即可
*/
public static SSLParams getSslSocketFactory(InputStream bksFile, String password, X509TrustManager trustManager) {
return getSslSocketFactoryBase(trustManager, bksFile, password);
}
private static SSLParams getSslSocketFactoryBase(X509TrustManager trustManager, InputStream bksFile, String password, InputStream... certificates) {
SSLParams sslParams = new SSLParams();
try {
KeyManager[] keyManagers = prepareKeyManager(bksFile, password);
TrustManager[] trustManagers = prepareTrustManager(certificates);
X509TrustManager manager;
if (trustManager != null) {
//优先使用用户自定义的TrustManager
manager = trustManager;
} else if (trustManagers != null) {
//然后使用默认的TrustManager
manager = chooseTrustManager(trustManagers);
} else {
//否则使用不安全的TrustManager
manager = UnSafeTrustManager;
}
// 创建TLS类型的SSLContext对象, that uses our TrustManager
SSLContext sslContext = SSLContext.getInstance("TLS");
// 用上面得到的trustManagers初始化SSLContext,这样sslContext就会信任keyStore中的证书
// 第一个参数是授权的密钥管理器,用来授权验证,比如授权自签名的证书验证。第二个是被授权的证书管理器,用来验证服务器端的证书
sslContext.init(keyManagers, new TrustManager[]{manager}, null);
// 通过sslContext获取SSLSocketFactory对象
sslParams.sSLSocketFactory = sslContext.getSocketFactory();
sslParams.trustManager = manager;
return sslParams;
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
} catch (KeyManagementException e) {
throw new AssertionError(e);
}
}
private static KeyManager[] prepareKeyManager(InputStream bksFile, String password) {
try {
if (bksFile == null || password == null) return null;
KeyStore clientKeyStore = KeyStore.getInstance("BKS");
clientKeyStore.load(bksFile, password.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(clientKeyStore, password.toCharArray());
return kmf.getKeyManagers();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static TrustManager[] prepareTrustManager(InputStream... certificates) {
if (certificates == null || certificates.length <= 0) return null;
try {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
// 创建一个默认类型的KeyStore,存储我们信任的证书
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
int index = 0;
for (InputStream certStream : certificates) {
String certificateAlias = Integer.toString(index++);
// 证书工厂根据证书文件的流生成证书 cert
Certificate cert = certificateFactory.generateCertificate(certStream);
// 将 cert 作为可信证书放入到keyStore中
keyStore.setCertificateEntry(certificateAlias, cert);
try {
if (certStream != null) certStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//我们创建一个默认类型的TrustManagerFactory
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
//用我们之前的keyStore实例初始化TrustManagerFactory,这样tmf就会信任keyStore中的证书
tmf.init(keyStore);
//通过tmf获取TrustManager数组,TrustManager也会信任keyStore中的证书
return tmf.getTrustManagers();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static X509TrustManager chooseTrustManager(TrustManager[] trustManagers) {
for (TrustManager trustManager : trustManagers) {
if (trustManager instanceof X509TrustManager) {
return (X509TrustManager) trustManager;
}
}
return null;
}
/**
* 为了解决客户端不信任服务器数字证书的问题,网络上大部分的解决方案都是让客户端不对证书做任何检查,
* 这是一种有很大安全漏洞的办法
*/
public static X509TrustManager UnSafeTrustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
};
/**
* 此类是用于主机名验证的基接口。 在握手期间,如果 URL 的主机名和服务器的标识主机名不匹配,
* 则验证机制可以回调此接口的实现程序来确定是否应该允许此连接。策略可以是基于证书的或依赖于其他验证方案。
* 当验证 URL 主机名使用的默认规则失败时使用这些回调。如果主机名是可接受的,则返回 true
*/
public static HostnameVerifier UnSafeHostnameVerifier = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
}
HttpUtils.calss
/**
* @author Mr.release
* @create 2019/8/2
* @Describe
*/
public class HttpUtils {
@SuppressLint("CheckResult")
public static <T> void ext(Flowable<T> flowable, IView view, boolean isShowLoading) {
flowable.compose(RxUtil.rxSchedulerHelper())
.doOnSubscribe(new Consumer<Subscription>() {
@Override
public void accept(Subscription subscription) throws Exception {
if (isShowLoading) view.showLoading();
}
})
.as(RxUtil.bindLifecycle((LifecycleOwner) view))
.subscribeWith(new CommonSubscriber<T>() {
@Override
protected void _onNext(T bean) {
Logger.d("_onNext: " + bean);
view.loadData(bean);
}
@Override
protected void _onError(String message) {
Logger.d("_onError: " + message);
if (isShowLoading)
view.showError();
else
view.showError(App.getInstance().getString(R.string.data_error));
}
@Override
protected void _onComplete() {
view.hideLoading();
}
});
}
}